#include <assert.h>
#include <stdio.h>
#include <stdlib.h>

#include "../src/qfunc.c"

typedef struct _QfuncTestDatum QfuncTestDatum;
struct _QfuncTestDatum 
{
  struct
    {
      double kappa;
      double logalpha[3];
      double tau[4*(5-1)];
      double gamma[(5-1)];
      double rho;
      double loglambda[4];
      double pz[3*5];
      double priorz[5];
      Rating ratings[8];
      double priorlogalphastddev;
      double priortaustddev;
      double priorgamma1mean;
      double priorgamma1stddev;
      double priorgamma2mean;
      double priorgamma2stddev;
      double priorgamma3mean;
      double priorgamma3stddev;
      double priorgamma4mean;
      double priorgamma4stddev;
      double priorkappamean;
      double priorkappastddev;
      double priorrhomean;
      double priorrhostddev;
      double priorloglambdastddev;
    }                           input;

  double                        output;
};

static void
test_qfunc (void)
{
  QfuncTestDatum data[] = 
    {{{0.712449, {0.444741, 0.955266, 0.0121878}, {0.112179, 0.494879,0.00490805, 0.491249, 0.981319, 0.636175, 0.876461, 0.161133,0.682905, 0.184716, 0.801592, 0.589255, 0.971518, 0.201261,0.684786, 0.24913}, {0.449264, 0.559287, 0.855356, 0.137639},0.736815, {0.114546, 0.90009, 0.125451, 0.624636}, {0.619667,0.895181, 0.634202, 0.643317, 0.983492, 0.0187201, 0.473069,0.960412, 0.798776, 0.217128, 0.883815, 0.988893, 0.597515,0.532342, 0.634685}, {0.539629, 0.0382282, 0.676986, 0.497046,0.802815}, {{1, 0, 3}, {1, 2, 0}, {3, 1, 1}, {1, 2, 1}, {2, 2,4}, {1, 0, 2}, {2, 1, 4}, {0, 1, 3}}, 0.923682, 0.776897,0.371596, 0.178179, 0.304015, 0.881715, 0.737394, 0.534862,0.320523, 0.862995, 0.264325, 0.57445, 0.521747, 0.645867,0.38051}, -274.946}, {{0.585557, {0.924232, 0.113525,0.745825}, {0.0459271, 0.886004, 0.436539, 0.248779, 0.243113,0.962322, 0.659643, 0.877183, 0.0649341, 0.658307, 0.777928,0.139789, 0.530072, 0.337784, 0.914933, 0.875464}, {0.955622,0.816037, 0.269065, 0.494954},0.370066, {0.891805, 0.15554, 0.749129, 0.324139}, {0.00580067,0.719, 0.50035, 0.081026, 0.0434787, 0.0593575, 0.623167,0.0160919, 0.385172, 0.28143, 0.483378, 0.48602, 0.0473877,0.366497, 0.607914}, {0.530397, 0.231351, 0.097432, 0.11296,0.160332}, {{0, 0, 3}, {1, 2, 3}, {1, 0, 0}, {2, 2, 2}, {0, 1,0}, {3, 0, 1}, {2, 2, 0}, {2, 1, 0}}, 0.339546, 0.941892,0.36383, 0.836193, 0.333746, 0.222892, 0.86348, 0.755167, 0.290267,0.163534, 0.240313, 0.739075, 0.905096, 0.882105,0.756934}, -214.702}, {{0.253055, {0.857708, 0.515607,0.149021}, {0.722658, 0.626357, 0.418175, 0.0360611, 0.562327,0.28681, 0.476283, 0.672231, 0.726134, 0.953065, 0.253391,0.808751, 0.970967, 0.662797, 0.0898569, 0.568438}, {0.231892,0.757702, 0.207752, 0.811503},0.978836, {0.899994, 0.692145, 0.662483, 0.256178}, {0.273637,0.273969, 0.626422, 0.693851, 0.986827, 0.797686, 0.954191,0.967718, 0.0337624, 0.544295, 0.14544, 0.996751, 0.370965,0.454438, 0.577003}, {0.764859, 0.613263, 0.246686, 0.765499,0.786023}, {{1, 2, 4}, {1, 2, 0}, {1, 2, 2}, {3, 1, 4}, {0, 0,4}, {2, 2, 4}, {3, 2, 1}, {0, 2, 2}}, 0.713269, 0.554541,0.103016, 0.529845, 0.439632, 0.280571, 0.476595, 0.835994,0.452805, 0.482885, 0.522404, 0.868276, 0.419042, 0.93859,0.376963}, -132.175}, {{0.871525, {0.0480772, 0.484152,0.799961}, {0.106666, 0.434814, 0.237467, 0.0344614, 0.320643,0.721545, 0.682926, 0.931445, 0.790798, 0.281914, 0.402355,0.45485, 0.954804, 0.829109, 0.919469, 0.932447}, {0.0865273,0.410067, 0.980879, 0.555483},0.215002, {0.36199, 0.496727, 0.755523, 0.108336}, {0.927176,0.25926, 0.721061, 0.787693, 0.20563, 0.576334, 0.789616,0.996896, 0.923717, 0.17398, 0.334766, 0.042092, 0.0946078,0.25451, 0.402319}, {0.955565, 0.684541, 0.273631, 0.846836,0.740563}, {{1, 2, 1}, {3, 0, 2}, {1, 0, 3}, {1, 2, 4}, {2, 1,3}, {2, 0, 4}, {3, 2, 0}, {0, 0, 1}}, 0.322551, 0.776904,0.0913131, 0.632227, 0.395376, 0.517644, 0.370252, 0.844534,0.189745, 0.941309, 0.580635, 0.847638, 0.266029, 0.767329,0.245869}, -128.077}, {{0.805546, {0.171421, 0.512819,0.84355}, {0.849982, 0.48688, 0.239188, 0.996714, 0.109419,0.164329, 0.462284, 0.905401, 0.477192, 0.768953, 0.94464,0.535149, 0.632658, 0.579208, 0.00333085, 0.954514}, {0.78502,0.313179, 0.236002, 0.708645},0.979473, {0.141758, 0.723183, 0.865095, 0.129492}, {0.654878,0.483995, 0.868381, 0.0200729, 0.49055, 0.0217111, 0.962981,0.542881, 0.721597, 0.0770711, 0.427832, 0.910223, 0.142389,0.0737402, 0.473318}, {0.125203, 0.82921, 0.837739, 0.764673,0.14573}, {{3, 2, 3}, {3, 0, 0}, {3, 0, 3}, {2, 0, 2}, {3, 0,2}, {3, 0, 0}, {3, 2, 4}, {0, 2, 2}}, 0.687452, 0.114556,0.899578, 0.0162379, 0.0325735, 0.630561, 0.0311964, 0.996165,0.542024, 0.60885, 0.0682157, 0.453284, 0.820427, 0.531779,0.640384}, -171.174}, {{0.543061, {0.678038, 0.458039,0.167066}, {0.417858, 0.848828, 0.6203, 0.402393, 0.272128,0.161376, 0.505744, 0.502816, 0.25589, 0.128803, 0.875183,0.471619, 0.259725, 0.586779, 0.266333, 0.403404}, {0.806441,0.766352, 0.734554, 0.76302},0.26338, {0.0883134, 0.276515, 0.595953, 0.845522}, {0.239485,0.656215, 0.19356, 0.573394, 0.0781089, 0.150471, 0.690744,0.317503, 0.949306, 0.275288, 0.219125, 0.0577777, 0.362527,0.00895552, 0.815721}, {0.251336, 0.596176, 0.274402, 0.052702,0.987956}, {{2, 0, 3}, {3, 0, 4}, {1, 1, 0}, {2, 0, 4}, {0, 1,4}, {2, 0, 3}, {0, 0, 0}, {1, 2, 0}}, 0.507862, 0.997887,0.456749, 0.142434, 0.268377, 0.341672, 0.263189, 0.569041,0.190268, 0.191201, 0.572445, 0.251538, 0.240962, 0.915912,0.35332}, -126.577}, {{0.19376, {0.878435, 0.906957,0.537598}, {0.942424, 0.282259, 0.632555, 0.484896, 0.954467,0.774397, 0.634668, 0.0281475, 0.812033, 0.50602, 0.292997,0.764959, 0.242992, 0.315752, 0.101796, 0.192514}, {0.991455,0.07479, 0.185884, 0.839194},0.797695, {0.196355, 0.278927, 0.301596, 0.855271}, {0.914096,0.646372, 0.8167, 0.900804, 0.139699, 0.0117034, 0.788552,0.0887706, 0.633679, 0.718707, 0.0235938, 0.845778, 0.317927,0.616911, 0.83108}, {0.854323, 0.243137, 0.431027, 0.991886,0.0566285}, {{0, 2, 3}, {2, 2, 0}, {3, 0, 0}, {0, 0, 0}, {0, 2,1}, {1, 0, 0}, {1, 0, 0}, {0, 1, 2}}, 0.046782, 0.1521, 0.69029,0.201357, 0.132686, 0.505728, 0.87359, 0.300554, 0.992987,0.494025, 0.0850376, 0.211783, 0.359307, 0.775318,0.0614437}, -789.112}, {{0.366005, {0.0413801, 0.158407,0.230364}, {0.511682, 0.798243, 0.727381, 0.238478, 0.455053,0.751461, 0.575281, 0.548188, 0.253696, 0.618775, 0.0695528,0.674598, 0.953142, 0.625788, 0.575528, 0.589561}, {0.741359,0.266481, 0.80021, 0.528117},0.375354, {0.225101, 0.641803, 0.297753, 0.863672}, {0.426858,0.914422, 0.0592752, 0.408619, 0.675397, 0.339141, 0.511087,0.154924, 0.0566222, 0.269589, 0.836489, 0.201781, 0.430834,0.69406, 0.246928}, {0.460422, 0.164353, 0.89385, 0.718811,0.0850681}, {{0, 1, 1}, {3, 2, 3}, {3, 1, 2}, {0, 1, 3}, {1, 1,2}, {2, 1, 0}, {1, 2, 4}, {1, 0, 1}}, 0.939252, 0.252047,0.421058, 0.221396, 0.512393, 0.337625, 0.361783, 0.812776,0.836996, 0.998484, 0.850696, 0.657853, 0.780374, 0.728895,0.0142069}, -918.072}, {{0.456071, {0.34954, 0.0348347,0.767279}, {0.995649, 0.185188, 0.140985, 0.0484678, 0.910581,0.245936, 0.888938, 0.62741, 0.689186, 0.733543, 0.551313,0.265627, 0.876409, 0.896547, 0.552829, 0.414932}, {0.218557,0.116173, 0.823934, 0.400725},0.762485, {0.766633, 0.789099, 0.633446, 0.766836}, {0.581445,0.648115, 0.584978, 0.856255, 0.335509, 0.759177, 0.957568,0.167069, 0.601966, 0.207864, 0.691941, 0.29066, 0.70542,0.655035, 0.277009}, {0.0721033, 0.589247, 0.831101, 0.876285,0.309618}, {{1, 1, 3}, {2, 0, 3}, {2, 1, 4}, {1, 0, 4}, {2, 1,4}, {1, 0, 4}, {1, 1, 0}, {2, 1, 4}}, 0.822614, 0.0420013,0.242839, 0.542782, 0.241169, 0.393887, 0.657861, 0.686527,0.90566, 0.63471, 0.700292, 0.519458, 0.303694, 0.426845,0.0083515}, -1157.84}, {{0.228798, {0.598274, 0.77181,0.731342}, {0.156695, 0.00902742, 0.940709, 0.855058, 0.847077,0.186413, 0.898708, 0.612219, 0.304294, 0.945244, 0.504822,0.954358, 0.617767, 0.0395832, 0.870112, 0.254066}, {0.0983093,0.735889, 0.443267, 0.245714},0.869511, {0.137615, 0.671457, 0.514372, 0.712817}, {0.128587,0.730747, 0.659314, 0.86574, 0.942174, 0.832039, 0.0470957,0.561446, 0.996931, 0.327217, 0.0927376, 0.943678, 0.957347,0.457105, 0.838672}, {0.845369, 0.221458, 0.0138382, 0.592958,0.975858}, {{3, 2, 0}, {0, 1, 0}, {2, 2, 3}, {2, 2, 4}, {1, 1,1}, {0, 0, 2}, {0, 1, 2}, {0, 2, 4}}, 0.0838436, 0.342382,0.0785859, 0.263041, 0.955256, 0.611634, 0.419271, 0.397301,0.0130821, 0.779595, 0.372176, 0.835856, 0.0161515, 0.452378,0.279438}, -334.754}};
  for (unsigned int i = 0; i < sizeof (data) / sizeof (data[0]); ++i)
    {
      ParameterizedNormalDistribution priorlogalpha = 
        parameterized_normal_distribution (data[i].input.priorlogalphastddev);

      ParameterizedNormalDistribution priortau =
        parameterized_normal_distribution (data[i].input.priortaustddev);

      NormalDistribution priorgammanormal[4] = {
          normal_distribution (data[i].input.priorgamma1mean,
                               data[i].input.priorgamma1stddev),
          normal_distribution (data[i].input.priorgamma2mean,
                               data[i].input.priorgamma2stddev),
          normal_distribution (data[i].input.priorgamma3mean,
                               data[i].input.priorgamma3stddev),
          normal_distribution (data[i].input.priorgamma4mean,
                               data[i].input.priorgamma4stddev)
      };

      Distribution* priorgamma[4] = {
          &priorgammanormal[0].base,
          &priorgammanormal[1].base,
          &priorgammanormal[2].base,
          &priorgammanormal[3].base
      };

      NormalDistribution priorkappa = 
        normal_distribution (data[i].input.priorkappamean,
                             data[i].input.priorkappastddev);

      NormalDistribution priorrho = 
        normal_distribution (data[i].input.priorrhomean,
                             data[i].input.priorrhostddev);

      ParameterizedNormalDistribution priorloglambda =
        parameterized_normal_distribution (data[i].input.priorloglambdastddev);

      double hq = 0;
      for (unsigned int k = 0; k < 3 * 5; ++k)
        {
          hq -= data[i].input.pz[k] * log (data[i].input.pz[k]);
        }

      double q = qfunc (data[i].input.kappa,
                        data[i].input.logalpha,
                        4,
                        5,
                        data[i].input.tau,
                        3,
                        data[i].input.gamma,
                        data[i].input.rho,
                        data[i].input.loglambda,
                        data[i].input.pz,
                        data[i].input.ratings,
                        8,
                        &priorkappa.base,
                        &priorlogalpha.base,
                        &priortau.base,
                        priorgamma,
                        &priorrho.base,
                        &priorloglambda.base,
                        hq);

      assert (      fabs (q - data[i].output) 
                 <= 1e-3 * (1 + fabs (q) + fabs (data[i].output))
              || (fprintf (stderr, "fail: %g != %g\n", q, data[i].output),
                  0));
    }
}

static void
test_dqfuncdkappa (void)
{
  QfuncTestDatum data[] = 
    {{{0.359778, {0.765348, 0.0156473, 0.917222}, {0.904685, 0.724406,  0.127853, 0.404713, 0.852299, 0.38048, 0.33797, 0.149617,  0.510433, 0.695312, 0.36182, 0.117596, 0.11244, 0.0308403,  0.11535, 0.554088}, {0.0538884, 0.6941, 0.357986, 0.277113},  0.694111, {0.928752, 0.342339, 0.359891, 0.789425}, {0.204346,  0.214485, 0.955178, 0.937127, 0.823865, 0.876516, 0.805561,  0.426694, 0.128554, 0.514695, 0.687965, 0.314254, 0.0977132,  0.399346, 0.133877}, {0.260366, 0.403613, 0.0413595, 0.856764,  0.566255}, {{3, 1, 0}, {3, 1, 1}, {0, 2, 0}, {2, 2, 4}, {0, 0,  3}, {3, 0, 0}, {2, 0, 4}, {1, 1, 4}}, 0.474861, 0.699021,  0.496873, 0.77683, 0.270515, 0.484535, 0.541695, 0.839703, 0.44665,  0.60802, 0.736135, 0.413009, 0.318096, 0.0933246, 0.0481698},  4.95096}, {{0.0987547, {0.220383, 0.693979, 0.914293}, {0.838389,  0.81677, 0.65262, 0.0575283, 0.272133, 0.341909, 0.953599,  0.560655, 0.495304, 0.0713935, 0.469063, 0.0189596, 0.655601,  0.624744, 0.861044, 0.282825}, {0.242592, 0.306648, 0.767719,  0.234655},  0.143837, {0.0862646, 0.0737398, 0.320362, 0.305448}, {0.269495,  0.42112, 0.262834, 0.0333148, 0.927586, 0.467521, 0.702179,  0.538011, 0.856193, 0.998458, 0.683219, 0.882411, 0.231449,  0.137414, 0.400395}, {0.639819, 0.924801, 0.369695, 0.165739,  0.495982}, {{1, 2, 1}, {3, 0, 1}, {1, 1, 0}, {0, 1, 0}, {2, 0,  2}, {0, 2, 2}, {2, 0, 2}, {0, 1, 2}}, 0.838537, 0.295956,  0.845377, 0.190534, 0.569042, 0.874835, 0.582543, 0.157219,  0.641456, 0.407314, 0.880364, 0.619208, 0.785263, 0.408856,  0.197144},  4.21787}, {{0.736797, {0.553814, 0.271442, 0.79675}, {0.0969783,  0.629013, 0.901746, 0.63101, 0.600996, 0.790476, 0.605791,  0.785633, 0.410463, 0.221434, 0.730955, 0.20309, 0.253244,  0.579979, 0.323641, 0.322727}, {0.634036, 0.794716, 0.914785,  0.125582},  0.897239, {0.240902, 0.643344, 0.328833, 0.800261}, {0.611889,  0.741598, 0.697822, 0.199264, 0.821412, 0.135807, 0.912189,  0.788802, 0.599978, 0.404852, 0.709099, 0.535558, 0.019999,  0.0812104, 0.386372}, {0.901522, 0.225283, 0.166425, 0.260789,  0.00428264}, {{2, 2, 1}, {3, 0, 2}, {3, 0, 0}, {1, 2, 1}, {1, 0,  3}, {1, 1, 1}, {2, 0, 4}, {1, 1, 2}}, 0.984382, 0.523081,  0.931957, 0.204022, 0.372493, 0.781484, 0.234134, 0.00475757,  0.551081, 0.645677, 0.321945, 0.215956, 0.951103, 0.240825,  0.612847}, -9.50255}, {{0.680398, {0.931104, 0.159615,  0.226475}, {0.778876, 0.705821, 0.99319, 0.965686, 0.774594,  0.721439, 0.470108, 0.0337289, 0.570572, 0.348946, 0.688624,  0.799595, 0.565814, 0.797865, 0.0429473, 0.477649}, {0.349858,  0.846762, 0.802122, 0.864802},  0.66946, {0.915658, 0.642507, 0.638327, 0.890584}, {0.209837,  0.649318, 0.672642, 0.11599, 0.488398, 0.179209, 0.638913,  0.545418, 0.139452, 0.490585, 0.839318, 0.979604, 0.341587,  0.447638, 0.361669}, {0.629745, 0.494825, 0.645516, 0.496867,  0.960285}, {{0, 0, 2}, {0, 0, 4}, {2, 0, 2}, {0, 0, 2}, {0, 1,  4}, {3, 2, 4}, {2, 2, 0}, {1, 0, 2}}, 0.579167, 0.00300846,  0.858539, 0.0697011, 0.36933, 0.353691, 0.185898, 0.953711,  0.880932, 0.174481, 0.546985, 0.408293, 0.74148, 0.683896,  0.707667}, -2.9587}, {{0.428689, {0.399893, 0.236258,  0.345998}, {0.798944, 0.905068, 0.590743, 0.849131, 0.838659,  0.325901, 0.587734, 0.990592, 0.768958, 0.956571, 0.234043,  0.804694, 0.815247, 0.0756396, 0.059562, 0.257709}, {0.406954,  0.33416, 0.375666, 0.550042},  0.978264, {0.934267, 0.139407, 0.204044, 0.17932}, {0.0291993,  0.548665, 0.354913, 0.340661, 0.703298, 0.96093, 0.364321,  0.571703, 0.746727, 0.726887, 0.559627, 0.756456, 0.671087,  0.667325, 0.301918}, {0.349502, 0.336927, 0.291659, 0.751876,  0.371237}, {{1, 1, 0}, {0, 1, 3}, {1, 1, 2}, {3, 2, 2}, {2, 0,  1}, {3, 0, 2}, {1, 0, 1}, {1, 0, 4}}, 0.40266, 0.152252,  0.547832, 0.191917, 0.373461, 0.603587, 0.192919, 0.851257,  0.670163, 0.642657, 0.828598, 0.279554, 0.923436, 0.91577,  0.268971},  3.24268}, {{0.523098, {0.252349, 0.248445, 0.967053}, {0.173596,  0.915421, 0.956786, 0.215177, 0.802359, 0.512761, 0.804534,  0.667346, 0.610442, 0.1393, 0.200947, 0.474427, 0.759185,  0.469137, 0.55829, 0.645829}, {0.479631, 0.545701, 0.64252,  0.376859},  0.956533, {0.293353, 0.394075, 0.409806, 0.782937}, {0.377932,  0.437289, 0.194629, 0.980578, 0.865171, 0.632754, 0.527284,  0.370136, 0.725871, 0.431808, 0.0528566, 0.610951, 0.256734,  0.873518, 0.407027}, {0.13132, 0.711032, 0.230998, 0.0301683,  0.174787}, {{1, 2, 3}, {3, 0, 4}, {3, 2, 1}, {1, 0, 3}, {0, 1,  0}, {3, 1, 3}, {1, 1, 4}, {1, 1, 3}}, 0.417679, 0.836923,  0.620362, 0.39185, 0.0397476, 0.399635, 0.425733, 0.411273,  0.174577, 0.76688, 0.89845, 0.0411366, 0.448706, 0.335073,  0.845593},  221.228}, {{0.430186, {0.191972, 0.461555, 0.438566}, {0.298866,  0.48094, 0.230557, 0.408397, 0.124079, 0.0632606, 0.393634,  0.788035, 0.732229, 0.0235129, 0.993999, 0.362302, 0.320956,  0.848936, 0.227119, 0.463853}, {0.279819, 0.40023, 0.892046,  0.61826},  0.849634, {0.208258, 0.430491, 0.179694, 0.550768}, {0.727318,  0.199934, 0.771297, 0.426689, 0.664057, 0.806301, 0.983261,  0.69446, 0.640545, 0.812302, 0.620959, 0.373504, 0.791608,  0.585183, 0.157107}, {0.0936852, 0.391378, 0.693137, 0.538847,  0.244051}, {{1, 2, 1}, {3, 2, 0}, {2, 2, 0}, {2, 1, 2}, {1, 1,  1}, {3, 1, 3}, {1, 1, 2}, {1, 1, 1}}, 0.18312, 0.262646,  0.359153, 0.693283, 0.455802, 0.0627111, 0.587857, 0.266594,  0.791745, 0.25641, 0.604595, 0.572134, 0.1512, 0.444109,  0.983636}, -5.38565}, {{0.19863, {0.359592, 0.858926,  0.826529}, {0.104944, 0.968213, 0.165789, 0.287682, 0.860893,  0.785093, 0.903143, 0.928529, 0.167609, 0.329291, 0.840432,  0.340672, 0.901015, 0.537546, 0.584022, 0.736077}, {0.328881,  0.386346, 0.139913, 0.752441},  0.130251, {0.0267544, 0.280987, 0.925912, 0.0253071}, {0.0585409,  0.115199, 0.63823, 0.164414, 0.273448, 0.212055, 0.709701,  0.996805, 0.944157, 0.371623, 0.369029, 0.0957896, 0.40661,  0.787601, 0.632952}, {0.766909, 0.0202643, 0.647688, 0.880511,  0.636657}, {{0, 0, 3}, {1, 1, 0}, {0, 0, 3}, {0, 1, 3}, {3, 0,  4}, {2, 0, 1}, {1, 0, 4}, {2, 0, 2}}, 0.99351, 0.366701,  0.954599, 0.61135, 0.934969, 0.251502, 0.316369, 0.446936,  0.661521, 0.0394466, 0.606668, 0.450131, 0.717365, 0.667824,  0.237639},  3.48198}, {{0.354342, {0.310754, 0.880222, 0.604687}, {0.587433,  0.29049, 0.232534, 0.724176, 0.950776, 0.29698, 0.865834,  0.769577, 0.339426, 0.362011, 0.614332, 0.453207, 0.89249,  0.70049, 0.574885, 0.846539}, {0.442358, 0.983125, 0.907062,  0.6089},  0.0880167, {0.672371, 0.0268393, 0.00421284, 0.500584}, {0.381881,  0.794305, 0.280037, 0.549808, 0.0849007, 0.928471, 0.51046,  0.210382, 0.72289, 0.314139, 0.0572529, 0.317892, 0.0224003,  0.739254, 0.210714}, {0.875534, 0.0392755, 0.832192, 0.601814,  0.787517}, {{2, 1, 2}, {3, 0, 1}, {2, 0, 4}, {2, 0, 4}, {2, 2,  2}, {0, 1, 3}, {0, 1, 2}, {2, 1, 3}}, 0.366905, 0.805353,  0.597601, 0.286934, 0.985024, 0.0110482, 0.317564, 0.737126,  0.900124, 0.0825771, 0.807104, 0.526744, 0.177234, 0.768438,  0.749851},  7.07412}, {{0.208851, {0.154833, 0.0291837, 0.539137}, {0.333317,  0.115558, 0.196991, 0.937323, 0.5458, 0.748653, 0.391638,  0.339722, 0.258866, 0.763629, 0.38059, 0.0221583, 0.52174,  0.863505, 0.298013, 0.215054}, {0.994997, 0.686272, 0.529575,  0.465203},  0.786146, {0.531438, 0.500391, 0.926066, 0.452829}, {0.41588,  0.3034, 0.988743, 0.907029, 0.667227, 0.911762, 0.64902, 0.648163,  0.903598, 0.531172, 0.626862, 0.126423, 0.040093, 0.233159,  0.411808}, {0.131426, 0.353821, 0.703584, 0.946604,  0.34528}, {{1, 2, 3}, {2, 0, 3}, {2, 2, 2}, {1, 1, 0}, {2, 0,  1}, {0, 2, 0}, {0, 2, 1}, {0, 2, 0}}, 0.822383, 0.203193,  0.0205379, 0.892451, 0.406503, 0.899793, 0.0317951, 0.985422,  0.739276, 0.988031, 0.382775, 0.337259, 0.835678, 0.456859,  0.755913}, 1.67192}};

  for (unsigned int i = 0; i < sizeof (data) / sizeof (data[0]); ++i)
    {
      ParameterizedNormalDistribution priorlogalpha = 
        parameterized_normal_distribution (data[i].input.priorlogalphastddev);

      ParameterizedNormalDistribution priortau =
        parameterized_normal_distribution (data[i].input.priortaustddev);

      NormalDistribution priorgammanormal[4] = {
          normal_distribution (data[i].input.priorgamma1mean,
                               data[i].input.priorgamma1stddev),
          normal_distribution (data[i].input.priorgamma2mean,
                               data[i].input.priorgamma2stddev),
          normal_distribution (data[i].input.priorgamma3mean,
                               data[i].input.priorgamma3stddev),
          normal_distribution (data[i].input.priorgamma4mean,
                               data[i].input.priorgamma4stddev)
      };

      Distribution* priorgamma[4] = {
          &priorgammanormal[0].base,
          &priorgammanormal[1].base,
          &priorgammanormal[2].base,
          &priorgammanormal[3].base
      };

      NormalDistribution priorkappa = 
        normal_distribution (data[i].input.priorkappamean,
                             data[i].input.priorkappastddev);

      NormalDistribution priorrho = 
        normal_distribution (data[i].input.priorrhomean,
                             data[i].input.priorrhostddev);

      ParameterizedNormalDistribution priorloglambda =
        parameterized_normal_distribution (data[i].input.priorloglambdastddev);

      double dkappa;
      double dlogalpha[3];
      double dtau[4*(5-1)];
      double dgamma[(5-1)];
      double drho;
      double dloglambda[4];

      dqfunc (&dkappa,
              dlogalpha,
              dtau,
              dgamma,
              &drho,
              dloglambda,
              data[i].input.kappa,
              data[i].input.logalpha,
              4,
              5,
              data[i].input.tau,
              3,
              data[i].input.gamma,
              data[i].input.rho,
              data[i].input.loglambda,
              data[i].input.pz,
              data[i].input.ratings,
              8,
              &priorkappa.base,
              &priorlogalpha.base,
              &priortau.base,
              priorgamma,
              &priorrho.base,
              &priorloglambda.base);

      assert (      fabs (dkappa - data[i].output) 
                 <= 1e-3 * (1 + fabs (dkappa) + fabs (data[i].output))
              || (fprintf (stderr, "fail: %g != %g\n", dkappa, data[i].output),
                  0));
    }
}

typedef struct _DQfuncDlogalphaTestDatum DQfuncDlogalphaTestDatum;
struct _DQfuncDlogalphaTestDatum
{
  struct
    {
      double kappa;
      double logalpha[3];
      double tau[4*(5-1)];
      double gamma[(5-1)];
      double rho;
      double loglambda[4];
      double pz[3*5];
      double priorz[5];
      Rating ratings[8];
      double priorlogalphastddev;
      double priortaustddev;
      double priorgamma1mean;
      double priorgamma1stddev;
      double priorgamma2mean;
      double priorgamma2stddev;
      double priorgamma3mean;
      double priorgamma3stddev;
      double priorgamma4mean;
      double priorgamma4stddev;
      double priorkappamean;
      double priorkappastddev;
      double priorrhomean;
      double priorrhostddev;
      double priorloglambdastddev;
    }                           input;


  double                        dlogalpha[3];
};

static void
test_dqfuncdlogalpha (void)
{
  DQfuncDlogalphaTestDatum data[] = 
    {{{0.391406, {0.48459, 0.674991, 0.00268359}, {0.891897, 0.17132,  0.62177, 0.476631, 0.218412, 0.370779, 0.320195, 0.0657085,  0.49285, 0.368796, 0.89379, 0.467595, 0.207877, 0.845869,  0.177777, 0.411788}, {0.933357, 0.0107425, 0.0476294, 0.49985},  0.541951, {0.526153, 0.372639, 0.497167, 0.650053}, {0.354832,  0.750869, 0.0205357, 0.431641, 0.984054, 0.430674, 0.954827,  0.938791, 0.615257, 0.536884, 0.487232, 0.730914, 0.769389,  0.359107, 0.0754448}, {0.797558, 0.758646, 0.311477, 0.575595,  0.255607}, {{0, 0, 4}, {0, 0, 3}, {1, 1, 2}, {0, 2, 2}, {0, 0,  4}, {1, 0, 2}, {1, 0, 4}, {2, 2, 3}}, 0.232493, 0.938839,  0.0784282, 0.605554, 0.877661, 0.18797, 0.0578925, 0.173912,  0.893608, 0.757296, 0.103065, 0.235121, 0.27835, 0.220412,  0.615833}, {-46.6371, -41.0651, -6.5874}}, {{0.504207, {0.508961,  0.861306, 0.540388}, {0.706649, 0.750315, 0.549828, 0.964793,  0.451042, 0.517822, 0.610989, 0.886365, 0.845488, 0.640161,  0.423019, 0.828473, 0.671576, 0.746553, 0.665723,  0.725407}, {0.436455, 0.468203, 0.445311, 0.109575},  0.932248, {0.959242, 0.584005, 0.569186, 0.225599}, {0.208926,  0.0341768, 0.604393, 0.774557, 0.691105, 0.423187, 0.718028,  0.929069, 0.0509437, 0.000168168, 0.889555, 0.257493, 0.30439,  0.334445, 0.164148}, {0.821038, 0.836187, 0.889134, 0.0545734,  0.88879}, {{1, 2, 3}, {2, 2, 0}, {2, 1, 0}, {2, 1, 4}, {2, 0,  4}, {3, 2, 4}, {0, 0, 0}, {2, 0, 4}}, 0.876946, 0.305129,  0.485387, 0.663191, 0.668019, 0.270953, 0.880994, 0.888634,  0.976915, 0.847765, 0.162966, 0.959565, 0.925971, 0.847597,  0.27341}, {-85.8052, -30.8384, -35.0189}}, {{0.702071, {0.621581,  0.513152, 0.109263}, {0.881033, 0.785393, 0.624017, 0.0546891,  0.992243, 0.908448, 0.318888, 0.569302, 0.329052, 0.240428,  0.0479354, 0.688308, 0.440418, 0.263514, 0.20017,  0.525343}, {0.480853, 0.337543, 0.352573, 0.251932},  0.778782, {0.715962, 0.839421, 0.14267, 0.897749}, {0.930569,  0.215404, 0.0879804, 0.905506, 0.0221212, 0.896516, 0.518678,  0.576455, 0.781693, 0.84858, 0.83037, 0.136037, 0.518179, 0.64841,  0.305027}, {0.655184, 0.180637, 0.295837, 0.0530954,  0.876402}, {{3, 2, 4}, {2, 2, 2}, {0, 0, 2}, {1, 1, 0}, {0, 1,  3}, {1, 0, 0}, {1, 0, 2}, {1, 0, 3}}, 0.464675, 0.456416,  0.910426, 0.978653, 0.534106, 0.241012, 0.822446, 0.0731461,  0.511985, 0.344496, 0.303767, 0.496691, 0.730292, 0.495916,  0.473397}, {-116.602, -115.666, -9.42523}}, {{0.360654, {0.212113,  0.847506, 0.16837}, {0.705471, 0.0314758, 0.551669, 0.115274,  0.829069, 0.566801, 0.095253, 0.204848, 0.850416, 0.0326948,  0.854241, 0.382403, 0.77727, 0.52071, 0.509745,  0.0786357}, {0.280579, 0.790418, 0.0138296, 0.605238},  0.919925, {0.578305, 0.166324, 0.436869, 0.214454}, {0.546829,  0.614655, 0.321594, 0.385386, 0.980028, 0.519402, 0.116746,  0.534969, 0.947333, 0.665161, 0.734343, 0.757699, 0.426624,  0.155416, 0.655707}, {0.47712, 0.636206, 0.141586, 0.0504689,  0.557195}, {{0, 0, 0}, {0, 0, 3}, {2, 0, 2}, {2, 2, 0}, {1, 1,  1}, {0, 0, 4}, {1, 2, 2}, {1, 1, 3}}, 0.0579009, 0.975262,  0.6136, 0.34274, 0.511072, 0.360607, 0.292006, 0.957355, 0.531043,  0.841204, 0.17526, 0.422385, 0.58371, 0.176043,  0.440917}, {-38.1642, -215.105,  18.9418}}, {{0.664687, {0.157086, 0.0206272, 0.78521}, {0.187567,  0.52088, 0.879041, 0.734741, 0.630372, 0.46298, 0.903779,  0.121141, 0.287632, 0.951908, 0.543172, 0.829135, 0.330278,  0.420864, 0.701968, 0.653875}, {0.907892, 0.837154, 0.525925,  0.212958},  0.243206, {0.680068, 0.505298, 0.427748, 0.0556389}, {0.159188,  0.626257, 0.693007, 0.425266, 0.696208, 0.722478, 0.571867,  0.137634, 0.7443, 0.179306, 0.742732, 0.807356, 0.323436,  0.477338, 0.0888574}, {0.899464, 0.486281, 0.951413, 0.8759,  0.656258}, {{2, 1, 2}, {3, 0, 1}, {1, 2, 0}, {2, 1, 2}, {2, 1,  2}, {3, 0, 1}, {0, 1, 3}, {0, 0, 2}}, 0.806213, 0.446115,  0.448152, 0.600619, 0.647026, 0.819859, 0.755145, 0.175353,  0.950817, 0.097381, 0.183278, 0.0377185, 0.206517, 0.918075,  0.440546}, {-50.862, -33.1479, -33.8402}}, {{0.230362, {0.883081,  0.440738, 0.351688}, {0.330899, 0.3968, 0.489325, 0.475789,  0.674641, 0.590587, 0.0432094, 0.0276369, 0.0740218, 0.943561,  0.223351, 0.272492, 0.898669, 0.992744, 0.12597,  0.0892144}, {0.860951, 0.786227, 0.207894, 0.648668},  0.630589, {0.903145, 0.767156, 0.29698, 0.29969}, {0.506345,  0.277832, 0.821191, 0.625049, 0.915758, 0.234622, 0.793554,  0.551028, 0.972197, 0.0112716, 0.521062, 0.652358, 0.979453,  0.885302, 0.431848}, {0.791407, 0.193226, 0.677408, 0.783179,  0.160819}, {{3, 0, 2}, {2, 0, 1}, {2, 2, 2}, {3, 2, 0}, {2, 1,  2}, {1, 1, 4}, {2, 1, 1}, {0, 1, 1}}, 0.290081, 0.910251,  0.486199, 0.861129, 0.783736, 0.63242, 0.665008, 0.23608, 0.867978,  0.397797, 0.871454, 0.685052, 0.895781, 0.386526,  0.350392}, {-117.928, -87.8445, -66.8268}}, {{0.0326939, {0.916328,  0.501224, 0.918544}, {0.241286, 0.723102, 0.823816, 0.135365,  0.0804675, 0.43302, 0.913564, 0.649166, 0.219339, 0.649285,  0.281145, 0.984158, 0.983259, 0.781307, 0.883347,  0.112704}, {0.298207, 0.885526, 0.496821, 0.762312},  0.265513, {0.969198, 0.995598, 0.843769, 0.0242262}, {0.246097,  0.171782, 0.708404, 0.943759, 0.813076, 0.258217, 0.0592383,  0.72442, 0.163792, 0.977073, 0.0750807, 0.741161, 0.382485,  0.0937253, 0.962377}, {0.442955, 0.496959, 0.596904, 0.200064,  0.177442}, {{0, 1, 2}, {3, 1, 3}, {1, 1, 4}, {0, 1, 3}, {2, 1,  1}, {2, 1, 1}, {0, 0, 1}, {1, 1, 3}}, 0.527761, 0.601306,  0.356296, 0.153216, 0.281664, 0.429525, 0.647892, 0.209457,  0.468588, 0.171307, 0.588653, 0.485037, 0.304796, 0.194235,  0.513573}, {-125.931, -215.543, -3.18043}}, {{0.743876, {0.922311,  0.10051, 0.551196}, {0.300921, 0.425352, 0.503606, 0.351132,  0.123479, 0.897591, 0.902299, 0.994836, 0.970263, 0.615928,  0.472775, 0.346945, 0.760806, 0.14734, 0.301467,  0.758291}, {0.275769, 0.842544, 0.107232, 0.244718},  0.531893, {0.920233, 0.00672263, 0.693522, 0.230972}, {0.494881,  0.503117, 0.34239, 0.107493, 0.59729, 0.600818, 0.347554,  0.137231, 0.981363, 0.128043, 0.00060947, 0.376425, 0.834023,  0.826576, 0.242318}, {0.100656, 0.991478, 0.719343, 0.9976,  0.568763}, {{3, 2, 1}, {0, 1, 3}, {2, 2, 2}, {3, 0, 4}, {2, 1,  1}, {3, 0, 4}, {0, 1, 4}, {2, 1, 0}}, 0.0712448, 0.712621,  0.304078, 0.337791, 0.576363, 0.209504, 0.961687, 0.230298,  0.979073, 0.608686, 0.614133, 0.0930671, 0.997711, 0.480643,  0.613524}, {-40.5156,  63.1746, -23.2528}}, {{0.716642, {0.163688, 0.654068,  0.371206}, {0.615986, 0.17221, 0.934724, 0.373606, 0.0472223,  0.100965, 0.222104, 0.0695278, 0.709431, 0.524602, 0.0125999,  0.10784, 0.479133, 0.545528, 0.403914, 0.493707}, {0.386066,  0.547818, 0.92327, 0.880183},  0.669424, {0.38413, 0.269202, 0.508977, 0.0534384}, {0.21192,  0.334478, 0.135372, 0.00621609, 0.110955, 0.112374, 0.0658438,  0.296785, 0.586353, 0.0997745, 0.958004, 0.817652, 0.0408245,  0.695861, 0.464297}, {0.431585, 0.493007, 0.772591, 0.584114,  0.762161}, {{2, 2, 4}, {1, 1, 1}, {2, 1, 2}, {1, 2, 2}, {1, 1,  4}, {2, 1, 0}, {0, 2, 2}, {2, 1, 4}}, 0.108877, 0.503388,  0.0751368, 0.708723, 0.896957, 0.16891, 0.939765, 0.702507,  0.786003, 0.0565359, 0.873921, 0.405722, 0.19965, 0.956761,  0.915918}, {46.6462, -64.8603, -5.7343}}, {{0.58807, {0.158825,  0.260901, 0.451621}, {0.156485, 0.665819, 0.48831, 0.867507,  0.394323, 0.556941, 0.984922, 0.79237, 0.6856, 0.659984, 0.816011,  0.852605, 0.983093, 0.873981, 0.759475, 0.978684}, {0.577372,  0.674332, 0.802714, 0.062766},  0.989301, {0.515506, 0.541814, 0.611145, 0.832817}, {0.849688,  0.0535037, 0.743638, 0.438493, 0.292746, 0.0685821, 0.951268,  0.752893, 0.632762, 0.252571, 0.0986624, 0.7698, 0.758781,  0.493095, 0.119979}, {0.192428, 0.0844493, 0.690381, 0.0572126,  0.203127}, {{0, 0, 1}, {3, 1, 1}, {1, 2, 1}, {3, 0, 2}, {3, 1,  0}, {1, 2, 1}, {1, 0, 0}, {3, 0, 1}}, 0.568943, 0.148568,  0.446068, 0.37031, 0.719255, 0.0950641, 0.70243, 0.931817,  0.426509, 0.026482, 0.751162, 0.178924, 0.793746, 0.773911,  0.6525}, {-81.6253, -62.348, -40.5892}}};

  for (unsigned int i = 0; i < sizeof (data) / sizeof (data[0]); ++i)
    {
      ParameterizedNormalDistribution priorlogalpha = 
        parameterized_normal_distribution (data[i].input.priorlogalphastddev);

      ParameterizedNormalDistribution priortau =
        parameterized_normal_distribution (data[i].input.priortaustddev);

      NormalDistribution priorgammanormal[4] = {
          normal_distribution (data[i].input.priorgamma1mean,
                               data[i].input.priorgamma1stddev),
          normal_distribution (data[i].input.priorgamma2mean,
                               data[i].input.priorgamma2stddev),
          normal_distribution (data[i].input.priorgamma3mean,
                               data[i].input.priorgamma3stddev),
          normal_distribution (data[i].input.priorgamma4mean,
                               data[i].input.priorgamma4stddev)
      };

      Distribution* priorgamma[4] = {
          &priorgammanormal[0].base,
          &priorgammanormal[1].base,
          &priorgammanormal[2].base,
          &priorgammanormal[3].base
      };

      NormalDistribution priorkappa = 
        normal_distribution (data[i].input.priorkappamean,
                             data[i].input.priorkappastddev);

      NormalDistribution priorrho = 
        normal_distribution (data[i].input.priorrhomean,
                             data[i].input.priorrhostddev);

      ParameterizedNormalDistribution priorloglambda =
        parameterized_normal_distribution (data[i].input.priorloglambdastddev);

      double dkappa;
      double dlogalpha[3];
      double dtau[4*(5-1)];
      double dgamma[(5-1)];
      double drho;
      double dloglambda[4];

      dqfunc (&dkappa,
              dlogalpha,
              dtau,
              dgamma,
              &drho,
              dloglambda,
              data[i].input.kappa,
              data[i].input.logalpha,
              4,
              5,
              data[i].input.tau,
              3,
              data[i].input.gamma,
              data[i].input.rho,
              data[i].input.loglambda,
              data[i].input.pz,
              data[i].input.ratings,
              8,
              &priorkappa.base,
              &priorlogalpha.base,
              &priortau.base,
              priorgamma,
              &priorrho.base,
              &priorloglambda.base);

      for (unsigned int j = 0; j < 3; ++j)
        {
          assert (      fabs (dlogalpha[j] - data[i].dlogalpha[j]) 
                     <= 5e-3 * (1 + fabs (dlogalpha[j]) + fabs (data[i].dlogalpha[j]))
                  || (fprintf (stderr, "fail: %g != %g\n", dlogalpha[j], data[i].dlogalpha[j]),
                      0));
        }
    }
}

typedef struct _DQfuncDtauTestDatum DQfuncDtauTestDatum;
struct _DQfuncDtauTestDatum
{
  struct
    {
      double kappa;
      double logalpha[3];
      double tau[4*(5-1)];
      double gamma[(5-1)];
      double rho;
      double loglambda[4];
      double pz[3*5];
      double priorz[5];
      Rating ratings[8];
      double priorlogalphastddev;
      double priortaustddev;
      double priorgamma1mean;
      double priorgamma1stddev;
      double priorgamma2mean;
      double priorgamma2stddev;
      double priorgamma3mean;
      double priorgamma3stddev;
      double priorgamma4mean;
      double priorgamma4stddev;
      double priorkappamean;
      double priorkappastddev;
      double priorrhomean;
      double priorrhostddev;
      double priorloglambdastddev;
    }                           input;

  double                        dtau[4*(5-1)];
};

static void
test_dqfuncdtau (void)
{
  DQfuncDtauTestDatum data[] = 
    {{{0.60306, {0.805581, 0.33004, 0.540567}, {0.847282, 0.385708,  0.902198, 0.430506, 0.742427, 0.722735, 0.341362, 0.498931,  0.424293, 0.404477, 0.410809, 0.968021, 0.483246, 0.129208,  0.626711, 0.804206}, {0.354356, 0.864464, 0.103382, 0.789995},  0.751296, {0.0588836, 0.773341, 0.249428, 0.904014}, {0.673176,  0.871143, 0.818922, 0.161587, 0.950441, 0.529782, 0.319992,  0.737294, 0.545965, 0.118973, 0.35197, 0.254048, 0.416757,  0.492262, 0.547764}, {0.899692, 0.552292, 0.38888, 0.757769,  0.148396}, {{3, 1, 2}, {3, 1, 4}, {1, 1, 4}, {1, 0, 4}, {1, 1,  2}, {2, 2, 3}, {1, 2, 4}, {2, 0, 3}}, 0.493409, 0.615538,  0.508341, 0.244382, 0.820233, 0.744395, 0.689418, 0.082795,  0.869791, 0.214613, 0.369427, 0.345501, 0.323827, 0.0956401,  0.0174561}, {-1.30098, 1.26359, -2.10832,  0.948803, -8.27751, -7.37384, -1.70096, -1.17738, -2.03608, -1.2805, -3.77386, 9.49983, -3.08423, -1.33434, 2.55706,  3.10216}}, {{0.0914528, {0.90707, 0.603378, 0.469692}, {0.191761,  0.354778, 0.214499, 0.711922, 0.0433645, 0.86137, 0.598961,  0.203582, 0.798983, 0.0411369, 0.854566, 0.514164, 0.716188,  0.171346, 0.639953, 0.144737}, {0.370686, 0.847519, 0.544313,  0.127281},  0.279234, {0.940449, 0.940934, 0.657589, 0.0874729}, {0.585671,  0.726435, 0.945667, 0.0441084, 0.724301, 0.127475, 0.742085,  0.245126, 0.683164, 0.272909, 0.227921, 0.528938, 0.511819,  0.632956, 0.0831844}, {0.158252, 0.6643, 0.0886438, 0.955904,  0.879018}, {{1, 1, 0}, {0, 1, 1}, {2, 1, 1}, {2, 0, 4}, {2, 2,  1}, {2, 1, 0}, {2, 1, 4}, {2, 0, 1}}, 0.723851, 0.14771,  0.298314, 0.791545, 0.138181, 0.421275, 0.352648, 0.747437,  0.41388, 0.2938, 0.610563, 0.502311, 0.730715, 0.0208907,  0.382641}, {7.80651, 31.7245, 24.2085, -18.4301, 24.3772, 8.46752,  6.58058, 5.50668, -19.5378, 64.6795, 12.1755, 6.6647, -15.8355,  30.9913, -4.38352, -0.800074}}, {{0.973373, {0.218897, 0.387934,  0.299457}, {0.815121, 0.554597, 0.29929, 0.343554, 0.936103,  0.830745, 0.151581, 0.0452392, 0.144558, 0.692565, 0.730306,  0.692592, 0.397121, 0.278685, 0.436506, 0.0820289}, {0.89481,  0.54797, 0.415616, 0.699387},  0.921437, {0.329073, 0.0276814, 0.39993, 0.106316}, {0.774477,  0.728391, 0.0563769, 0.170213, 0.943731, 0.57681, 0.0111377,  0.0256555, 0.251167, 0.846504, 0.318546, 0.628535, 0.972482,  0.409998, 0.236517}, {0.733725, 0.424512, 0.994382, 0.53713,  0.812288}, {{3, 2, 2}, {0, 0, 4}, {3, 2, 0}, {2, 2, 0}, {1, 1,  0}, {1, 2, 2}, {2, 1, 0}, {3, 1, 1}}, 0.0954389, 0.966701,  0.137199, 0.705973, 0.320962, 0.23831, 0.0808223, 0.535759,  0.377231, 0.661499, 0.0696847, 0.510104, 0.126064, 0.814995,  0.751139}, {-0.882457, -1.24183, -1.27924, -1.35755, 1.60029,  1.07151, 5.09172, 5.19087, 8.72931, 6.94455, 6.39103, 6.2147,  3.50259, 5.55184, 8.63266,  8.64624}}, {{0.881569, {0.153583, 0.404997, 0.514621}, {0.147844,  0.729071, 0.410615, 0.977492, 0.335555, 0.633632, 0.443915,  0.840293, 0.629583, 0.312669, 0.205605, 0.75947, 0.0938234,  0.935438, 0.544106, 0.689786}, {0.58372, 0.809374, 0.729111,  0.938647},  0.702151, {0.655791, 0.324113, 0.424025, 0.554307}, {0.926721,  0.913498, 0.446534, 0.218751, 0.293089, 0.469583, 0.606241,  0.589168, 0.98042, 0.263978, 0.846771, 0.495345, 0.0449812,  0.719872, 0.156985}, {0.911625, 0.235607, 0.990762, 0.218339,  0.209475}, {{0, 0, 3}, {0, 1, 1}, {2, 2, 2}, {0, 2, 1}, {3, 2,  3}, {3, 1, 2}, {2, 2, 1}, {1, 2, 2}}, 0.579816, 0.666648,  0.794313, 0.655168, 0.653095, 0.75315, 0.347779, 0.436417,  0.360006, 0.283567, 0.741538, 0.847249, 0.379586, 0.019589,  0.894767}, {-2.51074, 9.88423, 9.64839,  12.5571, -0.668642, -1.43881, 3.80509, 2.92061, -3.31607, 3.03256,  8.48205, 6.67465, -0.921824, -4.03648, 3.92131,  9.79691}}, {{0.351904, {0.334605, 0.299717, 0.737782}, {0.440278,  0.098998, 0.308955, 0.519443, 0.230803, 0.519182, 0.642307,  0.72513, 0.575635, 0.866087, 0.889156, 0.377351, 0.139218,  0.506081, 0.605589, 0.635813}, {0.29197, 0.126495, 0.586,  0.741046},  0.940066, {0.791889, 0.286283, 0.00326397, 0.499788}, {0.692891,  0.977328, 0.483821, 0.268985, 0.173709, 0.335022, 0.758691,  0.693349, 0.307622, 0.445865, 0.38134, 0.554131, 0.801541,  0.840276, 0.745527}, {0.262162, 0.675047, 0.254276, 0.00448159,  0.322095}, {{0, 2, 3}, {1, 1, 4}, {0, 1, 2}, {2, 2, 4}, {1, 2,  3}, {0, 0, 2}, {3, 1, 4}, {0, 1, 0}}, 0.883157, 0.967993,  0.00121762, 0.822308, 0.190266, 0.990665, 0.517397, 0.553323,  0.0165567, 0.655643, 0.758706, 0.859974, 0.708935, 0.209778,  0.377366}, {3.31628, 2.60432, 17.6282,  30.9627, -0.893545, -2.03772, -2.21147,  6.06749, -0.936902, -1.70992, -1.42365, -0.961916, -0.209774, -1.1061, -0.995265, -1.40072}}, {{0.305842, {0.907393, 0.369501,  0.631839}, {0.0436809, 0.232347, 0.115225, 0.627357, 0.721585,  0.34919, 0.147232, 0.62614, 0.899278, 0.158924, 0.156567,  0.108743, 0.345955, 0.142367, 0.500924, 0.350037}, {0.485981,  0.433432, 0.291146, 0.972671},  0.180139, {0.526039, 0.921645, 0.340832, 0.136458}, {0.293692,  0.80642, 0.713474, 0.414872, 0.944503, 0.659188, 0.0873347,  0.515595, 0.785579, 0.502621, 0.978592, 0.16964, 0.643212,  0.001697, 0.628555}, {0.683658, 0.20978, 0.710551, 0.655884,  0.50352}, {{0, 2, 3}, {3, 1, 0}, {0, 0, 0}, {3, 2, 2}, {3, 1,  3}, {2, 0, 4}, {1, 1, 4}, {0, 0, 1}}, 0.683741, 0.788905,  0.315052, 0.367062, 0.390048, 0.982485, 0.601578, 0.952189,  0.445546, 0.323297, 0.514243, 0.436595, 0.659967, 0.820676,  0.535651}, {11.7767, 22.7833, 21.8828,  27.9818, -2.54636, -2.18984, -2.14099, -1.9186, -1.60044, -0.536437, -0.791087, 0.24352, 2.44902, 1.64676, 5.21233,  10.162}}, {{0.266955, {0.0167545, 0.818979, 0.907096}, {0.583297,  0.806975, 0.108428, 0.251212, 0.0797771, 0.123234, 0.319523,  0.93616, 0.712715, 0.733186, 0.337038, 0.334582, 0.760526,  0.28764, 0.0137406, 0.820339}, {0.323931, 0.627674, 0.193065,  0.284688},  0.0569758, {0.610919, 0.374086, 0.377591, 0.473679}, {0.803944,  0.265658, 0.126379, 0.393902, 0.68071, 0.946135, 0.190219,  0.681187, 0.947524, 0.609097, 0.855637, 0.920661, 0.659884,  0.595356, 0.0352978}, {0.59673, 0.0322106, 0.402292, 0.75061,  0.539754}, {{1, 0, 3}, {3, 2, 4}, {0, 0, 3}, {3, 1, 0}, {2, 2,  2}, {1, 1, 3}, {0, 1, 0}, {3, 2, 0}}, 0.421291, 0.0282058,  0.373019, 0.0660749, 0.617347, 0.762548, 0.24664, 0.672173,  0.936637, 0.816414, 0.0564216, 0.990986, 0.989112, 0.207317,  0.200785}, {-316.536, -216.562, 115.095, 54.8331, 305.253,  631.104, -162.919, -809.313, -491.543, -135.708, -173.01, -55.0398, -533.716, 441.971,  239.746, -661.815}}, {{0.0703255, {0.329228, 0.61196,  0.165487}, {0.473596, 0.297018, 0.209669, 0.414877, 0.933842,  0.875726, 0.181463, 0.0418575, 0.867767, 0.258379, 0.418914,  0.795217, 0.195594, 0.321742, 0.602501, 0.738796}, {0.204608,  0.33263, 0.395184, 0.538011},  0.134282, {0.00340188, 0.783224, 0.372524, 0.660687}, {0.706384,  0.573555, 0.957647, 0.726845, 0.830658, 0.392092, 0.915789,  0.859078, 0.572279, 0.973178, 0.120572, 0.663484, 0.250536,  0.370677, 0.381777}, {0.458876, 0.917906, 0.975493, 0.843766,  0.324594}, {{3, 0, 4}, {2, 2, 0}, {1, 0, 3}, {1, 2, 1}, {2, 0,  2}, {1, 1, 1}, {0, 1, 0}, {1, 2, 4}}, 0.914504, 0.192269,  0.471242, 0.663907, 0.20812, 0.618714, 0.513596, 0.937062,  0.377462, 0.226622, 0.597806, 0.0779846, 0.805183, 0.253444,  0.477234}, {-0.799397, 7.25575, 11.1239, 8.88592, -23.8707,  0.52843, 20.9447, 39.6768, -16.1438, 3.51843, 8.11997,  0.731761, -0.762059, -1.32886, -7.63736, -8.04911}}, {{0.414501, {0.554647, 0.882767, 0.0954573}, {0.955625, 0.636741, 0.907273,  0.251691, 0.631031, 0.722236, 0.715004, 0.780449, 0.967124,  0.514116, 0.0962896, 0.266853, 0.0300617, 0.136654, 0.869668,  0.669047}, {0.952077, 0.331471, 0.616224, 0.191813},  0.537576, {0.776824, 0.733457, 0.0963557, 0.581951}, {0.140083,  0.826184, 0.844664, 0.95092, 0.417847, 0.11118, 0.0642156,  0.983796, 0.903731, 0.0148901, 0.797362, 0.953734, 0.767077,  0.145222, 0.128315}, {0.00165743, 0.435606, 0.528999, 0.936502,  0.464081}, {{0, 2, 2}, {1, 2, 4}, {0, 0, 0}, {0, 1, 2}, {2, 2,  1}, {1, 0, 3}, {3, 2, 2}, {1, 1, 4}}, 0.658782, 0.795542,  0.840146, 0.88213, 0.518699, 0.969358, 0.995482, 0.93121, 0.100852,  0.858178, 0.931266, 0.947413, 0.197122, 0.843288,  0.133904}, {9.14034, 8.3532, 25.6005,  25.4871, -2.00275, -3.80727, -4.04112, 5.06133, -0.632201, 2.25845,  3.17202, 1.76165, 0.891441, -0.850015, 3.15017,  2.13235}}, {{0.993679, {0.430045, 0.698066, 0.00558891}, {0.992022,  0.994439, 0.169067, 0.0690867, 0.52794, 0.335657, 0.373525,  0.22894, 0.645811, 0.816958, 0.404167, 0.233458, 0.714601,  0.716105, 0.545989, 0.302192}, {0.767187, 0.518984, 0.702701,  0.168288},  0.773508, {0.0889383, 0.0046353, 0.162699, 0.781487}, {0.0944989,  0.835568, 0.0936121, 0.253547, 0.758842, 0.462043, 0.864672,  0.607736, 0.941884, 0.0578756, 0.631214, 0.893135, 0.225779,  0.511886, 0.329022}, {0.125948, 0.706795, 0.809185, 0.160734,  0.352439}, {{1, 1, 3}, {1, 0, 2}, {3, 2, 1}, {1, 1, 4}, {1, 1,  0}, {1, 1, 0}, {2, 0, 2}, {1, 2, 2}}, 0.617857, 0.80455,  0.998035, 0.570952, 0.523358, 0.968982, 0.904423, 0.317406,  0.764516, 0.506939, 0.0397514, 0.70967, 0.822632, 0.449063,  0.408538}, {-0.347342, -0.73452, 0.824399, 0.153253, 9.54742,  8.32147, 13.2369, 16.4206, 0.0346022, -0.714879, 3.79095,  2.94932, -1.04279, 3.97528, 4.35955, 3.57034}}};

  for (unsigned int i = 0; i < sizeof (data) / sizeof (data[0]); ++i)
    {
      ParameterizedNormalDistribution priorlogalpha = 
        parameterized_normal_distribution (data[i].input.priorlogalphastddev);

      ParameterizedNormalDistribution priortau =
        parameterized_normal_distribution (data[i].input.priortaustddev);

      NormalDistribution priorgammanormal[4] = {
          normal_distribution (data[i].input.priorgamma1mean,
                               data[i].input.priorgamma1stddev),
          normal_distribution (data[i].input.priorgamma2mean,
                               data[i].input.priorgamma2stddev),
          normal_distribution (data[i].input.priorgamma3mean,
                               data[i].input.priorgamma3stddev),
          normal_distribution (data[i].input.priorgamma4mean,
                               data[i].input.priorgamma4stddev)
      };

      Distribution* priorgamma[4] = {
          &priorgammanormal[0].base,
          &priorgammanormal[1].base,
          &priorgammanormal[2].base,
          &priorgammanormal[3].base
      };

      NormalDistribution priorkappa = 
        normal_distribution (data[i].input.priorkappamean,
                             data[i].input.priorkappastddev);

      NormalDistribution priorrho = 
        normal_distribution (data[i].input.priorrhomean,
                             data[i].input.priorrhostddev);

      ParameterizedNormalDistribution priorloglambda =
        parameterized_normal_distribution (data[i].input.priorloglambdastddev);

      double dkappa;
      double dlogalpha[3];
      double dtau[4*(5-1)];
      double dgamma[(5-1)];
      double drho;
      double dloglambda[4];

      dqfunc (&dkappa,
              dlogalpha,
              dtau,
              dgamma,
              &drho,
              dloglambda,
              data[i].input.kappa,
              data[i].input.logalpha,
              4,
              5,
              data[i].input.tau,
              3,
              data[i].input.gamma,
              data[i].input.rho,
              data[i].input.loglambda,
              data[i].input.pz,
              data[i].input.ratings,
              8,
              &priorkappa.base,
              &priorlogalpha.base,
              &priortau.base,
              priorgamma,
              &priorrho.base,
              &priorloglambda.base);

      for (unsigned int j = 0; j < 4*(5-1); ++j)
        {
          assert (      fabs (dtau[j] - data[i].dtau[j]) 
                     <= 5e-3 * (1 + fabs (dtau[j]) + fabs (data[i].dtau[j]))
                  || (fprintf (stderr, "fail: %g != %g\n", dtau[j], data[i].dtau[j]),
                      0));
        }
    }
}

typedef struct _DQfuncDgammaTestDatum DQfuncDgammaTestDatum;
struct _DQfuncDgammaTestDatum
{
  struct
    {
      double kappa;
      double logalpha[3];
      double tau[4*(5-1)];
      double gamma[(5-1)];
      double rho;
      double loglambda[4];
      double pz[3*5];
      double priorz[5];
      Rating ratings[8];
      double priorlogalphastddev;
      double priortaustddev;
      double priorgamma1mean;
      double priorgamma1stddev;
      double priorgamma2mean;
      double priorgamma2stddev;
      double priorgamma3mean;
      double priorgamma3stddev;
      double priorgamma4mean;
      double priorgamma4stddev;
      double priorkappamean;
      double priorkappastddev;
      double priorrhomean;
      double priorrhostddev;
      double priorloglambdastddev;
    }                           input;

  double                        dgamma[(5-1)];
};

static void
test_dqfuncdgamma (void)
{
  DQfuncDgammaTestDatum data[] = 
    {{{0.711852, {0.335806, 0.794561, 0.813149}, {0.478327, 0.907763,  0.414586, 0.812039, 0.465063, 0.366477, 0.376743, 0.148482,  0.383576, 0.240207, 0.307737, 0.557392, 0.827896, 0.384931,  0.588434, 0.443526}, {0.367865, 0.527767, 0.678709, 0.966159},  0.656013, {0.191961, 0.884147, 0.15301, 0.177686}, {0.284197,  0.469561, 0.34097, 0.712623, 0.91772, 0.092818, 0.192488,  0.329047, 0.677513, 0.785081, 0.635096, 0.501151, 0.292582,  0.196647, 0.19157}, {0.133286, 0.764815, 0.517938, 0.225411,  0.477273}, {{1, 0, 1}, {1, 1, 2}, {3, 1, 1}, {3, 2, 4}, {1, 1,  1}, {0, 1, 0}, {0, 1, 4}, {1, 0, 2}}, 0.572854, 0.633791,  0.0724017, 0.299587, 0.288657, 0.16423, 0.731431, 0.586964,  0.370937, 0.0714118, 0.538943, 0.257917, 0.693424, 0.286331,  0.903847}, {-1.59067, -9.39229, -2.4045, -121.456}}, {{0.756767, {0.400842, 0.0896836, 0.712277}, {0.623481, 0.636027, 0.571745,  0.486866, 0.146208, 0.0631726, 0.937954, 0.414464, 0.846621,  0.774515, 0.773724, 0.683033, 0.259657, 0.403578, 0.702312,  0.14409}, {0.0017397, 0.710154, 0.415982, 0.240243},  0.244973, {0.309312, 0.326298, 0.527966, 0.621492}, {0.673285,  0.754553, 0.0410998, 0.475284, 0.610112, 0.816599, 0.626636,  0.628663, 0.835597, 0.0428748, 0.943603, 0.369007, 0.432019,  0.340562, 0.799513}, {0.367267, 0.721865, 0.924581, 0.55927,  0.122294}, {{2, 2, 1}, {3, 1, 4}, {1, 2, 4}, {3, 2, 4}, {2, 2,  3}, {3, 1, 4}, {2, 2, 1}, {2, 0, 4}}, 0.412553, 0.598283,  0.0313047, 0.500801, 0.739268, 0.84373, 0.990205, 0.0255172,  0.129156, 0.0271308, 0.363569, 0.396854, 0.293559, 0.984256,  0.419966}, {5.33942, -2.65038,  885.586, -148.772}}, {{0.0278471, {0.86154, 0.643694,  0.620453}, {0.66058, 0.139675, 0.719113, 0.0611828, 0.538287,  0.727122, 0.12083, 0.0298781, 0.0374851, 0.987854, 0.277101,  0.0396733, 0.0119679, 0.858698, 0.24997, 0.676104}, {0.615114,  0.565139, 0.265714, 0.256138},  0.587267, {0.703598, 0.62202, 0.635685, 0.926687}, {0.563923,  0.902907, 0.574502, 0.3884, 0.836801, 0.782077, 0.544624,  0.350915, 0.848947, 0.504976, 0.504951, 0.338947, 0.990249,  0.255006, 0.828847}, {0.723833, 0.42511, 0.989293, 0.572709,  0.136566}, {{3, 0, 3}, {0, 0, 0}, {2, 2, 4}, {3, 1, 4}, {2, 1,  2}, {0, 0, 3}, {2, 2, 3}, {1, 0, 4}}, 0.721512, 0.367273,  0.937024, 0.209879, 0.157589, 0.464366, 0.362522, 0.821479,  0.320788, 0.682289, 0.817898, 0.470564, 0.471841, 0.177313,  0.312947}, {-1.67821, 1.46678,  2.39833, -1.47514}}, {{0.131616, {0.481592, 0.922306,  0.4841}, {0.407783, 0.0564811, 0.933014, 0.911392, 0.271218,  0.334969, 0.565741, 0.974368, 0.0613384, 0.17738, 0.101376,  0.611846, 0.23986, 0.856593, 0.419087, 0.793949}, {0.769296,  0.384752, 0.241774, 0.481002},  0.63768, {0.90316, 0.319467, 0.996902, 0.229896}, {0.846679,  0.386454, 0.08551, 0.958679, 0.51171, 0.820712, 0.111142, 0.89734,  0.33433, 0.719337, 0.499296, 0.657481, 0.477737, 0.30025,  0.705347}, {0.888185, 0.0929852, 0.0584762, 0.224345,  0.250505}, {{0, 2, 4}, {0, 0, 0}, {1, 0, 1}, {3, 2, 0}, {0, 0,  2}, {1, 1, 3}, {3, 1, 0}, {0, 0, 0}}, 0.189825, 0.739009,  0.227443, 0.020609, 0.343146, 0.352555, 0.141933, 0.0619304,  0.831435, 0.531843, 0.0307914, 0.16459, 0.497106, 0.812506,  0.531496}, {-1279.6, -0.542718, -24.1051,  3.74296}}, {{0.50711, {0.0193686, 0.512256, 0.826149}, {0.618925,  0.926383, 0.45378, 0.601804, 0.36842, 0.736559, 0.714771, 0.37436,  0.347811, 0.393413, 0.362216, 0.232427, 0.285881, 0.561978,  0.830373, 0.201636}, {0.12129, 0.0648718, 0.0178664, 0.67014},  0.614181, {0.0455032, 0.50561, 0.843991, 0.995256}, {0.11912,  0.0518304, 0.242187, 0.626836, 0.382561, 0.337059, 0.867827,  0.279025, 0.989148, 0.974844, 0.6354, 0.993144, 0.427171,  0.144471, 0.433764}, {0.871854, 0.362299, 0.126605, 0.763624,  0.257673}, {{1, 0, 1}, {2, 1, 1}, {3, 2, 2}, {0, 1, 4}, {3, 0,  0}, {3, 0, 2}, {0, 1, 4}, {1, 1, 0}}, 0.316796, 0.620994,  0.919633, 0.262417, 0.197676, 0.569164, 0.677446, 0.635581,  0.815115, 0.232104, 0.809619, 0.356557, 0.825966, 0.257261,  0.17422}, {14.5387, 6.52675,  7.5702, -0.603073}}, {{0.363412, {0.398796, 0.11279,  0.740456}, {0.491559, 0.036497, 0.986185, 0.976832, 0.233886,  0.719701, 0.365191, 0.0571987, 0.971469, 0.522026, 0.796027,  0.379753, 0.335887, 0.706911, 0.563922, 0.570134}, {0.979331,  0.880945, 0.306662, 0.395914},  0.615918, {0.482149, 0.193872, 0.655458, 0.12436}, {0.445652,  0.207687, 0.678627, 0.890474, 0.72595, 0.842496, 0.621428,  0.919005, 0.203925, 0.0464692, 0.241675, 0.583118, 0.497014,  0.482547, 0.671542}, {0.603788, 0.616069, 0.175885, 0.275627,  0.987869}, {{2, 2, 3}, {2, 2, 0}, {3, 0, 1}, {2, 0, 2}, {3, 1,  3}, {1, 0, 0}, {3, 2, 2}, {0, 0, 1}}, 0.13392, 0.982013,  0.620169, 0.86351, 0.688268, 0.774326, 0.941542, 0.973036,  0.962318, 0.93183, 0.320114, 0.0540303, 0.758393, 0.885361,  0.0784388}, {-2.43587, -1.91688, 2.21012,  1.06737}}, {{0.470912, {0.261379, 0.402814, 0.406897}, {0.867125,  0.645311, 0.226929, 0.13127, 0.879255, 0.51139, 0.244916,  0.511101, 0.0157457, 0.823122, 0.47059, 0.569558, 0.04271,  0.860804, 0.538759, 0.249444}, {0.98868, 0.102411, 0.653398,  0.171006},  0.517768, {0.841032, 0.250584, 0.764108, 0.650643}, {0.195721,  0.0236544, 0.632839, 0.771388, 0.684331, 0.778738, 0.121738,  0.755642, 0.861209, 0.308149, 0.55218, 0.712932, 0.000404282,  0.76939, 0.302735}, {0.724252, 0.897993, 0.115991, 0.13173,  0.206485}, {{0, 0, 1}, {3, 0, 2}, {1, 2, 1}, {1, 0, 4}, {1, 0,  1}, {1, 0, 2}, {1, 0, 2}, {0, 0, 2}}, 0.0569613, 0.865408,  0.367621, 0.555842, 0.86124, 0.841753, 0.734782, 0.784454,  0.176909, 0.0630149, 0.613044, 0.0288122, 0.315701, 0.754866,  0.0608646}, {-4.88076, 4.3169, -1.37977,  2.52457}}, {{0.31588, {0.315296, 0.985477, 0.758129}, {0.591628,  0.417303, 0.869485, 0.6264, 0.385143, 0.360342, 0.00407742,  0.258779, 0.829301, 0.499102, 0.162324, 0.523996, 0.0448473,  0.322193, 0.0993091, 0.910952}, {0.0160352, 0.00649218, 0.344443,  0.850088},  0.700155, {0.691196, 0.358966, 0.0919581, 0.108527}, {0.273893,  0.489481, 0.465558, 0.723384, 0.913551, 0.485404, 0.206779,  0.894082, 0.414449, 0.32308, 0.682783, 0.849235, 0.092256,  0.223771, 0.771831}, {0.8332, 0.0857638, 0.879328, 0.921743,  0.133045}, {{3, 1, 2}, {3, 2, 2}, {0, 2, 1}, {3, 0, 0}, {3, 1,  0}, {2, 2, 1}, {2, 1, 1}, {0, 2, 1}}, 0.394568, 0.520361,  0.829785, 0.0245178, 0.120675, 0.0308801, 0.364227, 0.301134,  0.207125, 0.545476, 0.157448, 0.407052, 0.792676, 0.222397,  0.474665}, {1360.31,  125.551, -0.677686, -6.15027}}, {{0.557817, {0.70042, 0.998626,  0.702834}, {0.724617, 0.614656, 0.119299, 0.781091, 0.591572,  0.220088, 0.598937, 0.951305, 0.567054, 0.0994127, 0.568057,  0.587078, 0.26592, 0.892288, 0.0225809, 0.429631}, {0.858868,  0.0996123, 0.800184, 0.954966},  0.301052, {0.399193, 0.801558, 0.252132, 0.576435}, {0.784537,  0.68226, 0.471042, 0.984863, 0.564449, 0.0833222, 0.519736,  0.417809, 0.465036, 0.515265, 0.932658, 0.151888, 0.572748,  0.492684, 0.503028}, {0.29302, 0.473136, 0.6925, 0.548061,  0.991968}, {{0, 2, 1}, {0, 1, 1}, {1, 2, 4}, {0, 2, 1}, {0, 2,  2}, {0, 2, 0}, {1, 0, 2}, {1, 0, 4}}, 0.073943, 0.890942,  0.295929, 0.415533, 0.289406, 0.208682, 0.824888, 0.430671,  0.724958, 0.12536, 0.305151, 0.012862, 0.259922, 0.610095,  0.372493}, {-4.88073,  6.15724, -2.25018, -15.9851}}, {{0.860974, {0.687174, 0.117411,  0.869465}, {0.567954, 0.214038, 0.424911, 0.321404, 0.575985,  0.140095, 0.53397, 0.0254747, 0.160452, 0.850689, 0.325288,  0.200587, 0.729781, 0.125731, 0.199928, 0.895436}, {0.716919,  0.86581, 0.589833, 0.522943},  0.855946, {0.178636, 0.472422, 0.653478, 0.287992}, {0.964597,  0.0475106, 0.332074, 0.712007, 0.824502, 0.513541, 0.306599,  0.551555, 0.973813, 0.188253, 0.106012, 0.821774, 0.848081,  0.988326, 0.210576}, {0.104855, 0.982272, 0.398493, 0.687633,  0.248909}, {{1, 0, 4}, {3, 1, 1}, {0, 1, 4}, {0, 0, 0}, {3, 2,  4}, {2, 1, 2}, {3, 0, 0}, {1, 2, 1}}, 0.803636, 0.926071,  0.0341549, 0.960917, 0.839039, 0.87856, 0.702081, 0.24891,  0.0145366, 0.36502, 0.395482, 0.697355, 0.0407237, 0.176766,  0.28947}, {-1.71133, -2.52147, 0.791171, -4.57235}}}; 

  for (unsigned int i = 0; i < sizeof (data) / sizeof (data[0]); ++i)
    {
      ParameterizedNormalDistribution priorlogalpha = 
        parameterized_normal_distribution (data[i].input.priorlogalphastddev);

      ParameterizedNormalDistribution priortau =
        parameterized_normal_distribution (data[i].input.priortaustddev);

      NormalDistribution priorgammanormal[4] = {
          normal_distribution (data[i].input.priorgamma1mean,
                               data[i].input.priorgamma1stddev),
          normal_distribution (data[i].input.priorgamma2mean,
                               data[i].input.priorgamma2stddev),
          normal_distribution (data[i].input.priorgamma3mean,
                               data[i].input.priorgamma3stddev),
          normal_distribution (data[i].input.priorgamma4mean,
                               data[i].input.priorgamma4stddev)
      };

      Distribution* priorgamma[4] = {
          &priorgammanormal[0].base,
          &priorgammanormal[1].base,
          &priorgammanormal[2].base,
          &priorgammanormal[3].base
      };

      NormalDistribution priorkappa = 
        normal_distribution (data[i].input.priorkappamean,
                             data[i].input.priorkappastddev);

      NormalDistribution priorrho = 
        normal_distribution (data[i].input.priorrhomean,
                             data[i].input.priorrhostddev);

      ParameterizedNormalDistribution priorloglambda =
        parameterized_normal_distribution (data[i].input.priorloglambdastddev);

      double dkappa;
      double dlogalpha[3];
      double dtau[4*(5-1)];
      double dgamma[(5-1)];
      double drho;
      double dloglambda[4];

      dqfunc (&dkappa,
              dlogalpha,
              dtau,
              dgamma,
              &drho,
              dloglambda,
              data[i].input.kappa,
              data[i].input.logalpha,
              4,
              5,
              data[i].input.tau,
              3,
              data[i].input.gamma,
              data[i].input.rho,
              data[i].input.loglambda,
              data[i].input.pz,
              data[i].input.ratings,
              8,
              &priorkappa.base,
              &priorlogalpha.base,
              &priortau.base,
              priorgamma,
              &priorrho.base,
              &priorloglambda.base);

      for (unsigned int j = 0; j < (5-1); ++j)
        {
          assert (      fabs (dgamma[j] - data[i].dgamma[j]) 
                     <= 5e-3 * (1 + fabs (dgamma[j]) + fabs (data[i].dgamma[j]))
                  || (fprintf (stderr, "fail: %g != %g\n", dgamma[j], data[i].dgamma[j]),
                      0));
        }
    }
}

static void
test_dqfuncdrho (void)
{
  QfuncTestDatum data[] = 
    {{{0.796526, {0.769656, 0.64492, 0.635616}, {0.518839, 0.312863,  0.551887, 0.0617465, 0.549313, 0.698407, 0.207396, 0.350253,  0.808539, 0.484525, 0.0913291, 0.103633, 0.562386, 0.0518366,  0.886765, 0.944925}, {0.969174, 0.187465, 0.176572, 0.528959},  0.172648, {0.417809, 0.531653, 0.893344, 0.653809}, {0.104946,  0.979765, 0.831597, 0.104496, 0.406539, 0.772369, 0.481345,  0.295957, 0.922014, 0.68104, 0.377711, 0.733571, 0.870177,  0.794276, 0.432787}, {0.764397, 0.682713, 0.617703, 0.903827,  0.591749}, {{1, 1, 3}, {2, 2, 1}, {1, 2, 1}, {2, 2, 1}, {2, 0,  4}, {2, 0, 2}, {2, 2, 2}, {3, 0, 4}}, 0.264904, 0.0860508,  0.0104833, 0.93794, 0.159958, 0.106286, 0.178886, 0.833444,  0.753419, 0.333916, 0.697541, 0.537488, 0.831405, 0.652876,  0.31983},  19.2012}, {{0.803917, {0.961228, 0.8586, 0.887043}, {0.0395198,  0.278515, 0.240897, 0.983216, 0.447771, 0.0136113, 0.154846,  0.972733, 0.509831, 0.853653, 0.0485602, 0.793847, 0.676387,  0.100234, 0.714644, 0.0963057}, {0.138899, 0.268829, 0.0617683,  0.776476},  0.334982, {0.307601, 0.203168, 0.889433, 0.295463}, {0.0290861,  0.962271, 0.906216, 0.847692, 0.0154748, 0.807426, 0.933483,  0.337861, 0.161821, 0.758865, 0.139637, 0.661474, 0.0615871,  0.0442214, 0.0433308}, {0.522575, 0.792758, 0.982453, 0.266855,  0.187593}, {{2, 1, 3}, {0, 2, 4}, {2, 2, 3}, {2, 2, 0}, {0, 0,  0}, {0, 2, 2}, {2, 2, 1}, {1, 0, 1}}, 0.485157, 0.779285,  0.377422, 0.89213, 0.45607, 0.817014, 0.471206, 0.0444384,  0.440596, 0.00958786, 0.537723, 0.706578, 0.278774, 0.250722,  0.398086},  1.35062}, {{0.0451037, {0.217187, 0.206501, 0.354755}, {0.522529,  0.424429, 0.224048, 0.0879002, 0.334936, 0.939273, 0.444763,  0.710478, 0.442806, 0.483202, 0.627749, 0.239272, 0.398367,  0.0426067, 0.618161, 0.701549}, {0.69179, 0.763832, 0.367439,  0.303463},  0.646686, {0.546645, 0.160938, 0.948708, 0.124157}, {0.122216,  0.93689, 0.860808, 0.789221, 0.182943, 0.492128, 0.15033,  0.346415, 0.699741, 0.864378, 0.911058, 0.948048, 0.657134,  0.246217, 0.209509}, {0.256258, 0.893302, 0.878778, 0.906046,  0.609572}, {{0, 1, 2}, {1, 0, 1}, {0, 1, 0}, {3, 1, 0}, {0, 2,  4}, {2, 2, 0}, {3, 2, 3}, {2, 0, 2}}, 0.346656, 0.71784,  0.957338, 0.485415, 0.22444, 0.78095, 0.0965302, 0.696194,  0.0414973, 0.288822, 0.9462, 0.349778, 0.341757, 0.424444,  0.0351419}, -654.587}, {{0.40173, {0.684623, 0.178227,  0.825633}, {0.145472, 0.791321, 0.299449, 0.919587, 0.535899,  0.444665, 0.581609, 0.962249, 0.0504843, 0.220224, 0.800659,  0.865719, 0.35429, 0.178727, 0.511837, 0.919519}, {0.00451215,  0.836971, 0.0873931, 0.884377},  0.602782, {0.152348, 0.909166, 0.0587438, 0.45731}, {0.361027,  0.609718, 0.139157, 0.921411, 0.916362, 0.0281089, 0.176908,  0.870926, 0.696138, 0.22745, 0.311189, 0.516636, 0.517411,  0.715613, 0.391671}, {0.512124, 0.68044, 0.62822, 0.507294,  0.909342}, {{3, 1, 2}, {2, 1, 0}, {3, 2, 2}, {3, 0, 2}, {1, 2,  4}, {0, 1, 1}, {3, 0, 4}, {1, 1, 1}}, 0.528092, 0.719054,  0.44855, 0.452032, 0.167065, 0.109336, 0.309393, 0.530621,  0.250703, 0.0812272, 0.132485, 0.659695, 0.554565, 0.853777,  0.821296}, -1.30191}, {{0.143059, {0.0371545, 0.138164,  0.429625}, {0.630935, 0.356714, 0.509944, 0.922331, 0.721593,  0.828622, 0.790891, 0.473781, 0.269562, 0.661556, 0.681554,  0.164388, 0.73894, 0.410853, 0.600327, 0.0319028}, {0.0792456,  0.856288, 0.74655, 0.210607},  0.936187, {0.819133, 0.608386, 0.780981, 0.305251}, {0.462419,  0.0984414, 0.85865, 0.583658, 0.633797, 0.307551, 0.384869,  0.314097, 0.972241, 0.625997, 0.22048, 0.575156, 0.561388,  0.0256693, 0.188578}, {0.49591, 0.7051, 0.27912, 0.977971,  0.559724}, {{0, 2, 4}, {1, 1, 4}, {2, 1, 2}, {0, 1, 3}, {2, 1,  4}, {2, 0, 3}, {2, 0, 1}, {1, 0, 4}}, 0.885967, 0.670734,  0.196989, 0.254472, 0.423548, 0.572293, 0.33834, 0.670814, 0.78975,  0.264742, 0.953471, 0.356718, 0.81751, 0.638745,  0.732991}, -2.58206}, {{0.781562, {0.256122, 0.613076,  0.544413}, {0.285651, 0.551022, 0.333956, 0.566442, 0.725927,  0.665055, 0.663222, 0.369453, 0.471455, 0.241508, 0.0909299,  0.0311132, 0.800641, 0.451757, 0.826188, 0.0776421}, {0.443923,  0.634248, 0.187443, 0.344652},  0.662361, {0.378126, 0.574367, 0.800239, 0.37671}, {0.827104,  0.240411, 0.233796, 0.650783, 0.162048, 0.577189, 0.864344,  0.179328, 0.920541, 0.486259, 0.83323, 0.378687, 0.468784,  0.660071, 0.755588}, {0.934764, 0.834536, 0.472627, 0.410937,  0.272403}, {{1, 0, 2}, {0, 0, 1}, {3, 2, 1}, {3, 0, 1}, {0, 1,  1}, {3, 2, 3}, {2, 0, 1}, {2, 0, 4}}, 0.45641, 0.89826, 0.610698,  0.895693, 0.629307, 0.657849, 0.376902, 0.244909, 0.467258,  0.0806604, 0.512558, 0.0655814, 0.546718, 0.594402,  0.679328}, -1.45412}, {{0.686894, {0.0779338, 0.934331,  0.923739}, {0.75213, 0.243398, 0.461704, 0.512803, 0.479727,  0.786987, 0.563443, 0.902104, 0.584034, 0.15768, 0.905594,  0.525202, 0.339125, 0.690422, 0.824934, 0.0126442}, {0.273543,  0.143705, 0.230532, 0.333316},  0.586649, {0.0657708, 0.296201, 0.409577, 0.83452}, {0.822373,  0.834498, 0.896774, 0.354793, 0.0353858, 0.271054, 0.99467,  0.770759, 0.877705, 0.36546, 0.469467, 0.431634, 0.187283,  0.540526, 0.456823}, {0.158091, 0.0435786, 0.309994, 0.123507,  0.571441}, {{2, 2, 4}, {3, 1, 2}, {3, 1, 1}, {2, 2, 4}, {2, 2,  0}, {1, 1, 1}, {0, 0, 3}, {0, 2, 2}}, 0.977808, 0.0137928,  0.71393, 0.736922, 0.155435, 0.179295, 0.817156, 0.382129,  0.120049, 0.908241, 0.822486, 0.61137, 0.242343, 0.542781,  0.353019}, -7.11088}, {{0.179736, {0.0550603, 0.00225462,  0.896195}, {0.0216457, 0.0114817, 0.692261, 0.772688, 0.450204,  0.0336739, 0.678468, 0.0587584, 0.713283, 0.878239, 0.499173,  0.241603, 0.331154, 0.75819, 0.590932, 0.419117}, {0.719784,  0.515847, 0.0481509, 0.0660983},  0.540048, {0.460787, 0.0458963, 0.169903, 0.518402}, {0.449305,  0.353636, 0.397215, 0.0681979, 0.415631, 0.675168, 0.338456,  0.354915, 0.537392, 0.175995, 0.0968535, 0.0237606, 0.779201,  0.585064, 0.677737}, {0.303976, 0.263354, 0.536913, 0.611638,  0.763928}, {{3, 2, 2}, {1, 0, 3}, {2, 1, 0}, {3, 2, 3}, {2, 1,  3}, {2, 0, 2}, {0, 2, 2}, {1, 0, 3}}, 0.802568, 0.491016,  0.441735, 0.245526, 0.353263, 0.137381, 0.0445208, 0.177328,  0.937632, 0.462213, 0.706065, 0.822413, 0.40024, 0.286218,  0.609211}, -4.30729}, {{0.798653, {0.621038, 0.701154,  0.931475}, {0.494676, 0.357684, 0.164241, 0.319836, 0.730748,  0.555116, 0.673225, 0.878101, 0.485222, 0.201854, 0.535844,  0.83358, 0.307894, 0.264222, 0.0736313, 0.127515}, {0.48548,  0.863982, 0.787414, 0.518304},  0.686828, {0.242944, 0.0862598, 0.58683, 0.192152}, {0.88526,  0.922019, 0.266993, 0.461404, 0.330144, 0.248794, 0.388893,  0.976182, 0.12829, 0.712949, 0.555313, 0.668288, 0.864068,  0.639318, 0.427798}, {0.182808, 0.0000856064, 0.851904, 0.909494,  0.49598}, {{0, 1, 3}, {0, 2, 2}, {1, 2, 0}, {0, 1, 4}, {1, 1,  4}, {0, 1, 2}, {0, 1, 4}, {0, 1, 1}}, 0.757141, 0.765644,  0.322664, 0.303829, 0.871881, 0.843626, 0.0556707, 0.842425,  0.541737, 0.594832, 0.666778, 0.866243, 0.413447, 0.881883,  0.111465}, -132.279}, {{0.197955, {0.549379, 0.242565,  0.683668}, {0.0151468, 0.549293, 0.390661, 0.774174, 0.519167,  0.792152, 0.625016, 0.45151, 0.215338, 0.920271, 0.78139,  0.395839, 0.372913, 0.378533, 0.186558, 0.729061}, {0.50667,  0.965086, 0.304675, 0.617596},  0.308715, {0.415707, 0.0621102, 0.933928, 0.293568}, {0.866414,  0.67145, 0.159755, 0.774402, 0.0742618, 0.0464336, 0.708245,  0.559064, 0.153991, 0.265043, 0.312406, 0.186151, 0.775458,  0.0784856, 0.583344}, {0.679481, 0.810371, 0.773811, 0.965748,  0.370767}, {{2, 2, 3}, {3, 0, 3}, {2, 1, 2}, {1, 2, 3}, {0, 1,  4}, {3, 2, 0}, {3, 0, 3}, {3, 1, 0}}, 0.394664, 0.7117, 0.03182,  0.0771985, 0.52825, 0.0402508, 0.872065, 0.302797, 0.453989,  0.993817, 0.163821, 0.743733, 0.299998, 0.728774, 0.851415},  0.632572}};


  for (unsigned int i = 0; i < sizeof (data) / sizeof (data[0]); ++i)
    {
      ParameterizedNormalDistribution priorlogalpha = 
        parameterized_normal_distribution (data[i].input.priorlogalphastddev);

      ParameterizedNormalDistribution priortau =
        parameterized_normal_distribution (data[i].input.priortaustddev);

      NormalDistribution priorgammanormal[4] = {
          normal_distribution (data[i].input.priorgamma1mean,
                               data[i].input.priorgamma1stddev),
          normal_distribution (data[i].input.priorgamma2mean,
                               data[i].input.priorgamma2stddev),
          normal_distribution (data[i].input.priorgamma3mean,
                               data[i].input.priorgamma3stddev),
          normal_distribution (data[i].input.priorgamma4mean,
                               data[i].input.priorgamma4stddev)
      };

      Distribution* priorgamma[4] = {
          &priorgammanormal[0].base,
          &priorgammanormal[1].base,
          &priorgammanormal[2].base,
          &priorgammanormal[3].base
      };

      NormalDistribution priorkappa = 
        normal_distribution (data[i].input.priorkappamean,
                             data[i].input.priorkappastddev);

      NormalDistribution priorrho = 
        normal_distribution (data[i].input.priorrhomean,
                             data[i].input.priorrhostddev);

      ParameterizedNormalDistribution priorloglambda =
        parameterized_normal_distribution (data[i].input.priorloglambdastddev);

      double dkappa;
      double dlogalpha[3];
      double dtau[4*(5-1)];
      double dgamma[(5-1)];
      double drho;
      double dloglambda[4];

      dqfunc (&dkappa,
              dlogalpha,
              dtau,
              dgamma,
              &drho,
              dloglambda,
              data[i].input.kappa,
              data[i].input.logalpha,
              4,
              5,
              data[i].input.tau,
              3,
              data[i].input.gamma,
              data[i].input.rho,
              data[i].input.loglambda,
              data[i].input.pz,
              data[i].input.ratings,
              8,
              &priorkappa.base,
              &priorlogalpha.base,
              &priortau.base,
              priorgamma,
              &priorrho.base,
              &priorloglambda.base);

      assert (      fabs (drho - data[i].output) 
                 <= 1e-3 * (1 + fabs (drho) + fabs (data[i].output))
              || (fprintf (stderr, "fail: %g != %g\n", drho, data[i].output),
                  0));
    }
}

typedef struct _DQfuncDloglambdaTestDatum DQfuncDloglambdaTestDatum;
struct _DQfuncDloglambdaTestDatum
{
  struct
    {
      double kappa;
      double logalpha[3];
      double tau[4*(5-1)];
      double gamma[(5-1)];
      double rho;
      double loglambda[4];
      double pz[3*5];
      double priorz[5];
      Rating ratings[8];
      double priorlogalphastddev;
      double priortaustddev;
      double priorgamma1mean;
      double priorgamma1stddev;
      double priorgamma2mean;
      double priorgamma2stddev;
      double priorgamma3mean;
      double priorgamma3stddev;
      double priorgamma4mean;
      double priorgamma4stddev;
      double priorkappamean;
      double priorkappastddev;
      double priorrhomean;
      double priorrhostddev;
      double priorloglambdastddev;
    }                           input;


  double                        dloglambda[4];
};

static void
test_dqfuncdloglambda (void)
{
  DQfuncDloglambdaTestDatum data[] = 
    {{{0.345868, {0.220667, 0.619021, 0.00822625}, {0.386884, 0.15127,  0.066897, 0.750055, 0.166953, 0.401666, 0.769863, 0.383064,  0.915349, 0.761485, 0.937972, 0.515992, 0.110254, 0.823992,  0.707346, 0.791733}, {0.190767, 0.0214923, 0.0926714, 0.555262},  0.844899, {0.800825, 0.473651, 0.547035, 0.458015}, {0.649556,  0.406754, 0.79698, 0.291061, 0.24789, 0.63689, 0.413916, 0.375712,  0.486405, 0.698919, 0.897925, 0.265458, 0.662413, 0.991572,  0.106192}, {0.0746911, 0.640921, 0.898901, 0.55093,  0.229792}, {{1, 0, 3}, {3, 2, 4}, {0, 0, 0}, {3, 1, 1}, {0, 1,  1}, {3, 2, 3}, {1, 2, 0}, {2, 2, 3}}, 0.840096, 0.42525,  0.00389462, 0.771778, 0.19054, 0.0184969, 0.206914, 0.480717,  0.94265, 0.381606, 0.792998, 0.105005, 0.456244, 0.682688,  0.895073}, {-95.5836, -32.9719, -9.8214, -43.2958}}, {{0.839546, {0.793831, 0.691115, 0.788881}, {0.764855, 0.15291, 0.792214,  0.237951, 0.535063, 0.312814, 0.366964, 0.234057, 0.763285,  0.122275, 0.348467, 0.0271424, 0.282569, 0.179625, 0.966861,  0.234145}, {0.177564, 0.723381, 0.284173, 0.339071},  0.338018, {0.92955, 0.593058, 0.55019, 0.573162}, {0.77664,  0.800844, 0.312239, 0.0380992, 0.463826, 0.43388, 0.078182,  0.274814, 0.341551, 0.0854128, 0.0510396, 0.992245, 0.161926,  0.118552, 0.816895}, {0.814681, 0.438545, 0.834379, 0.477824,  0.476664}, {{3, 1, 0}, {1, 0, 1}, {1, 1, 3}, {3, 0, 2}, {3, 2,  4}, {1, 2, 0}, {3, 2, 0}, {0, 0, 3}}, 0.508995, 0.241322,  0.927634, 0.903501, 0.732355, 0.440478, 0.615395, 0.865402,  0.268529, 0.00659832, 0.537213, 0.590588, 0.926978, 0.921186,  0.486173}, {-26.6795, -111.885, -0.897649, -107.576}}, {{0.598343, {0.765052, 0.802633, 0.669278}, {0.783662, 0.326507, 0.968254,  0.191455, 0.306998, 0.817511, 0.726932, 0.263821, 0.403497,  0.0851562, 0.286454, 0.648426, 0.538094, 0.816627, 0.279856,  0.111213}, {0.947506, 0.889649, 0.35867, 0.62504},  0.349163, {0.124597, 0.556037, 0.955761, 0.565502}, {0.79809,  0.587783, 0.764306, 0.258504, 0.980579, 0.860851, 0.500485,  0.855007, 0.895422, 0.574396, 0.852059, 0.316913, 0.0787957,  0.29454, 0.740846}, {0.369406, 0.189147, 0.93587, 0.115806,  0.020243}, {{2, 1, 2}, {1, 0, 1}, {1, 1, 4}, {3, 0, 3}, {1, 2,  0}, {1, 0, 3}, {2, 0, 0}, {3, 0, 0}}, 0.0645506, 0.379833,  0.160045, 0.454741, 0.266461, 0.79205, 0.395739, 0.196238,  0.285882, 0.931199, 0.895253, 0.341231, 0.39046, 0.356802,  0.0431941}, {120.364, -253.303, -526.537, -230.969}}, {{0.024318, {0.311664, 0.0622619, 0.302348}, {0.654912, 0.122517, 0.126392,  0.186542, 0.634669, 0.0579664, 0.746559, 0.0264967, 0.179927,  0.791506, 0.95451, 0.630758, 0.98369, 0.505624, 0.023311,  0.735505}, {0.642459, 0.115164, 0.666509, 0.692311},  0.618141, {0.8035, 0.604247, 0.389963, 0.963229}, {0.680983,  0.477855, 0.203421, 0.328561, 0.623017, 0.731295, 0.176924,  0.148634, 0.831511, 0.776786, 0.546166, 0.164944, 0.325887,  0.753475, 0.810661}, {0.522485, 0.210723, 0.0869659, 0.118351,  0.904344}, {{3, 0, 1}, {1, 1, 1}, {2, 1, 4}, {2, 0, 3}, {3, 0,  1}, {0, 0, 3}, {1, 2, 0}, {1, 1, 4}}, 0.407223, 0.482719,  0.728388, 0.941114, 0.726241, 0.00486439, 0.524967, 0.612553,  0.103224, 0.273569, 0.348043, 0.46392, 0.271713, 0.496783,  0.801877}, {-14.0277, -88.9324, -10.8889, -83.6869}}, {{0.298976, {0.945826, 0.743309, 0.991216}, {0.776491, 0.735103, 0.656343,  0.872865, 0.872148, 0.327879, 0.173624, 0.144477, 0.931033,  0.601639, 0.168759, 0.61951, 0.31848, 0.498415, 0.89519,  0.271467}, {0.85456, 0.226701, 0.398407, 0.46959},  0.555584, {0.280875, 0.655098, 0.478374, 0.779093}, {0.545773,  0.998755, 0.605508, 0.906946, 0.217894, 0.825132, 0.461031,  0.975912, 0.616255, 0.656372, 0.841521, 0.657432, 0.117841,  0.761182, 0.570054}, {0.802872, 0.891139, 0.362775, 0.100464,  0.247287}, {{0, 1, 0}, {1, 2, 2}, {1, 0, 2}, {1, 0, 4}, {1, 1,  4}, {2, 1, 4}, {3, 1, 3}, {0, 2, 3}}, 0.610264, 0.707677,  0.622091, 0.468194, 0.0644909, 0.708921, 0.0165825, 0.561248,  0.846597, 0.88379, 0.555552, 0.585336, 0.230342, 0.227417,  0.714031}, {-71.5692, -123.724, -5.99338, -34.7264}}, {{0.927904, {0.112502, 0.466235, 0.143977}, {0.125033, 0.221363, 0.10346,  0.0435126, 0.877746, 0.611099, 0.395783, 0.421422, 0.409552,  0.546608, 0.686861, 0.404839, 0.848303, 0.700011, 0.803072,  0.849288}, {0.262967, 0.469668, 0.575655, 0.135257},  0.335063, {0.357167, 0.10942, 0.99128, 0.21003}, {0.135804,  0.00595982, 0.947767, 0.332284, 0.524705, 0.610177, 0.526345,  0.922732, 0.978097, 0.923315, 0.121506, 0.0744293, 0.278087,  0.120244, 0.272218}, {0.811462, 0.808418, 0.544589, 0.136962,  0.4764}, {{3, 0, 1}, {0, 2, 0}, {3, 0, 1}, {1, 2, 0}, {3, 0,  2}, {2, 0, 1}, {2, 1, 4}, {1, 1, 2}}, 0.451251, 0.435169,  0.145682, 0.26637, 0.315447, 0.429209, 0.197915, 0.934086,  0.790742, 0.819033, 0.671569, 0.0113533, 0.812645, 0.895717,  0.550063}, {-13.0801, -35.423, -43.5246, -37.9025}}, {{0.936924, {0.534558, 0.775474, 0.277845}, {0.125462, 0.72614, 0.230885,  0.140883, 0.649062, 0.274888, 0.795715, 0.995201, 0.382692,  0.959441, 0.366506, 0.797287, 0.448606, 0.168699, 0.547473,  0.125717}, {0.437253, 0.356055, 0.651756, 0.575654},  0.500329, {0.821497, 0.876283, 0.297809, 0.374867}, {0.0953572,  0.645398, 0.156926, 0.725805, 0.820469, 0.849683, 0.161724,  0.343113, 0.861028, 0.483177, 0.364438, 0.894507, 0.692328,  0.935703, 0.238721}, {0.457254, 0.336274, 0.283947, 0.663067,  0.956925}, {{1, 1, 1}, {3, 1, 1}, {1, 1, 0}, {0, 1, 4}, {1, 1,  1}, {2, 0, 3}, {3, 0, 3}, {3, 0, 0}}, 0.514777, 0.407665,  0.365258, 0.582058, 0.41942, 0.762267, 0.208332, 0.856253,  0.598951, 0.912584, 0.0466075, 0.51314, 0.737923, 0.429408,  0.68217}, {-5.5751, -219.809, -9.97944, -117.455}}, {{0.618633, {0.0455947, 0.493704, 0.443449}, {0.161379, 0.709321, 0.209757,  0.780382, 0.204454, 0.194544, 0.802092, 0.415125, 0.622396,  0.775124, 0.039825, 0.206793, 0.766143, 0.176174, 0.127241,  0.160185}, {0.253003, 0.43825, 0.697833, 0.478015},  0.63437, {0.392656, 0.204129, 0.0345663, 0.47299}, {0.683335,  0.994372, 0.254184, 0.268536, 0.488791, 0.19228, 0.839059,  0.64614, 0.713666, 0.152455, 0.632267, 0.879997, 0.537492,  0.0252141, 0.472082}, {0.626994, 0.0992419, 0.327381, 0.994066,  0.992624}, {{0, 2, 2}, {3, 2, 3}, {0, 1, 4}, {0, 1, 1}, {3, 1,  1}, {3, 1, 3}, {0, 0, 0}, {2, 2, 0}}, 0.706586, 0.123253, 0.9595,  0.519634, 0.0232515, 0.128881, 0.705316, 0.251098, 0.534461,  0.936601, 0.866257, 0.604958, 0.820795, 0.784147,  0.23399}, {-55.3487,  7.85808, -8.29501, -54.7818}}, {{0.724962, {0.283303, 0.758933,  0.761908}, {0.0979682, 0.184061, 0.431551, 0.767842, 0.105344,  0.477474, 0.308298, 0.808342, 0.58571, 0.454223, 0.179417,  0.103025, 0.334612, 0.919762, 0.242816, 0.236768}, {0.729654,  0.098967, 0.458669, 0.00277843},  0.00469177, {0.815665, 0.699736, 0.24087, 0.906724}, {0.631604,  0.268185, 0.473028, 0.801379, 0.15413, 0.959887, 0.664687,  0.215669, 0.699907, 0.780469, 0.561661, 0.881057, 0.780145,  0.537654, 0.324893}, {0.151403, 0.681178, 0.0789844, 0.322114,  0.146712}, {{3, 2, 3}, {0, 1, 3}, {0, 0, 1}, {2, 2, 0}, {1, 1,  2}, {3, 0, 0}, {2, 1, 3}, {3, 1, 2}}, 0.865513, 0.379248,  0.0812443, 0.239988, 0.233909, 0.111063, 0.608216, 0.438609,  0.0797796, 0.151176, 0.943529, 0.22294, 0.379873, 0.370707,  0.381868}, {-60.8902, -49.6339, -69.3543, -148.276}}, {{0.341882, {0.599728, 0.833053, 0.0569749}, {0.190479, 0.918551, 0.754069,  0.73486, 0.0437674, 0.0530377, 0.374821, 0.653616, 0.803779,  0.819129, 0.263758, 0.0454002, 0.365171, 0.739349, 0.112582,  0.101871}, {0.142231, 0.359476, 0.741876, 0.720003},  0.800349, {0.759747, 0.908823, 0.663028, 0.60987}, {0.841197,  0.154754, 0.928168, 0.566102, 0.788159, 0.779933, 0.274552,  0.762323, 0.969031, 0.516175, 0.229152, 0.397152, 0.229682,  0.403593, 0.12728}, {0.254921, 0.870206, 0.661717, 0.407277,  0.454572}, {{1, 0, 2}, {1, 2, 1}, {2, 0, 0}, {2, 0, 3}, {1, 1,  2}, {2, 0, 2}, {2, 0, 0}, {1, 1, 1}}, 0.110458, 0.752895,  0.744249, 0.844703, 0.269262, 0.598141, 0.816081, 0.278601,  0.481103, 0.818208, 0.541529, 0.516278, 0.512072, 0.302033,  0.312378}, {0.416086, -231.572, -238.778, 1.95203}}};

  for (unsigned int i = 0; i < sizeof (data) / sizeof (data[0]); ++i)
    {
      ParameterizedNormalDistribution priorlogalpha = 
        parameterized_normal_distribution (data[i].input.priorlogalphastddev);

      ParameterizedNormalDistribution priortau =
        parameterized_normal_distribution (data[i].input.priortaustddev);

      NormalDistribution priorgammanormal[4] = {
          normal_distribution (data[i].input.priorgamma1mean,
                               data[i].input.priorgamma1stddev),
          normal_distribution (data[i].input.priorgamma2mean,
                               data[i].input.priorgamma2stddev),
          normal_distribution (data[i].input.priorgamma3mean,
                               data[i].input.priorgamma3stddev),
          normal_distribution (data[i].input.priorgamma4mean,
                               data[i].input.priorgamma4stddev)
      };

      Distribution* priorgamma[4] = {
          &priorgammanormal[0].base,
          &priorgammanormal[1].base,
          &priorgammanormal[2].base,
          &priorgammanormal[3].base
      };

      NormalDistribution priorkappa = 
        normal_distribution (data[i].input.priorkappamean,
                             data[i].input.priorkappastddev);

      NormalDistribution priorrho = 
        normal_distribution (data[i].input.priorrhomean,
                             data[i].input.priorrhostddev);

      ParameterizedNormalDistribution priorloglambda =
        parameterized_normal_distribution (data[i].input.priorloglambdastddev);

      double dkappa;
      double dlogalpha[3];
      double dtau[4*(5-1)];
      double dgamma[(5-1)];
      double drho;
      double dloglambda[4];

      dqfunc (&dkappa,
              dlogalpha,
              dtau,
              dgamma,
              &drho,
              dloglambda,
              data[i].input.kappa,
              data[i].input.logalpha,
              4,
              5,
              data[i].input.tau,
              3,
              data[i].input.gamma,
              data[i].input.rho,
              data[i].input.loglambda,
              data[i].input.pz,
              data[i].input.ratings,
              8,
              &priorkappa.base,
              &priorlogalpha.base,
              &priortau.base,
              priorgamma,
              &priorrho.base,
              &priorloglambda.base);

      for (unsigned int j = 0; j < 4; ++j)
        {
          assert (      fabs (dloglambda[j] - data[i].dloglambda[j]) 
                     <= 5e-3 * (1 + fabs (dloglambda[j]) + fabs (data[i].dloglambda[j]))
                  || (fprintf (stderr, "fail: %g != %g\n", dloglambda[j], data[i].dloglambda[j]),
                      0));
        }
    }
}

int 
main (void)
{
  srand48 (69);

  test_qfunc ();
  test_dqfuncdkappa ();
  test_dqfuncdlogalpha ();
  test_dqfuncdtau ();
  test_dqfuncdgamma ();
  test_dqfuncdrho ();
  test_dqfuncdloglambda ();

  return 0;
}
